Can't see click ripple effect in Android Touch events - android

I've seen some solutions here, but none of them works for me. I am using View.OnTouchListener class to detect click and drag events in my app code. But that beautiful ripple effect is now gone (perhaps because I am consuming the MotionEvent gestures before it gets to the View.OnClickListener. Notice the return true in MotionEvent.ACTION_DOWN block).
I cannot use View.OnClickListener to detect click events because my app uses multiple composite gestures (click, click-hold, click-hold-drag, etc). Can anyone please share some pointers on how to create ripple effect with Android touch gestures?
Here is the code snippet for my View.OnTouchListener implementation inside a BaseAdapter class:
v.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if(mAppActionDownListener != null) {
mAppActionDownListener.onAppActionDown(appObjectList.get(position), v);
}
Log.d("COOK", "ACTION_DOWN: " + ev.getX() + ", " + ev.getY());
t1 = System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
Log.d("COOK", "ACTION_UP: " + ev.getX() + ", " + ev.getY());
t2 = System.currentTimeMillis();
if(Math.abs(t2-t1) <=300) {
//Toast.makeText(context, "Click event", Toast.LENGTH_SHORT).show();
if(mAppClickListener!=null) {
mAppClickListener.onAppClicked(appObjectList.get(position), v);
}
}
return false;
case MotionEvent.ACTION_MOVE:
Log.d("COOK", "ACTION_MOVE: " + ev.getX() + ", " + ev.getY());
ClipData.Item item = new ClipData.Item(appObjectList.get(position).getAppname()+"~"+appObjectList.get(position).getPackagename()+"~"+appObjectList.get(position).getAppicon());
ClipData dragData = new ClipData(
(CharSequence) v.getTag(),
new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN},
item);
v.findViewById(R.id.appicondrawable).startDrag(dragData, // the data to be dragged
new View.DragShadowBuilder(v.findViewById(R.id.appicondrawable)), // the drag shadow builder
null, // no need to use local data
0 // flags (not currently used, set to 0)
);
if(mAppDragListener!=null) {
mAppDragListener.onAppDragged(appObjectList.get(position), v);
}
return true;
default:
return false;
}
}
});
Any help would be greatly appreciated!
Update 1:
Just to clarify, setting up background/foreground/clickable attributes in the parent custom layout has no effect for reasons mentioned above. I have already tried those solutions.
Update 2:
Adding the adapter item layout code.:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
<ImageView
android:id="#+id/appicondrawable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:maxWidth="40dp"
android:maxHeight="40dp"
android:scaleType="fitCenter"
android:layout_marginStart="3dp"
android:src="#drawable/ic_launcher_background" />
<TextView
android:id="#+id/appname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:maxLines="1"
android:text="app name"
android:textAlignment="center"
android:textSize="10sp"
android:textColor="#000000" />
</LinearLayout>

I found a way around this. Although the ripple effect is not customisable, the fix is pretty nifty. I manually called the setPressed() method on View inside the ACTION_DOWN and ACTION_UP events and now I can see the default Android ripple effect.
case MotionEvent.ACTION_DOWN:
//icon.setColorFilter(Color.argb(80, 0, 0, 0));
v.setPressed(true);
if(mAppActionDownListener != null) {
mAppActionDownListener.onAppActionDown(appObjectList.get(position), v);
}
Log.d("COOK", "ACTION_DOWN: " + ev.getX() + ", " + ev.getY());
t1 = System.currentTimeMillis();
return true;
case MotionEvent.ACTION_UP:
v.setPressed(false);
Log.d("COOK", "ACTION_UP: " + ev.getX() + ", " + ev.getY());
t2 = System.currentTimeMillis();
if(Math.abs(t2-t1) <=300) {
//Toast.makeText(context, "Click event", Toast.LENGTH_SHORT).show();
if(mAppClickListener!=null) {
mAppClickListener.onAppClicked(appObjectList.get(position), v);
}
}

You need custom background or foreground to the layout.
Create a file named res/drawable/ripple_selector.xml:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="#android:id/mask"><color android:color="#dcffffff"/></item>
</ripple>
Then, use it as background:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/ripple_selector"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
...
</LinearLayout>
If does not work, try using it as foreground:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/applayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:foreground="#drawable/ripple_selector"
android:focusable="true"
android:clickable="true"
android:padding="5sp">
...
</LinearLayout>

to add a ripple effect to your view, you can add ?attr/selectableItemBackground as view's background.
<ImageView
android:height="100dp"
android:width="100dp"
android:src="#drawable/crush"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true" />

Related

How do I get the coordinates of an image same on all devices?

I tried out all the possible solutions but they are not working for me .
I have an ImageView with an image. I am able to get the coordinates on touch of the image, but when I click on same point of the Image in different resolution device the the coordinates are different.
I want that the coordinates must be the same on all devices , So that i am able to get the exact point where the image is touched .
My current code is:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView=(ImageView)findViewById(R.id.imageView);
final TextView coordinateText=(TextView)findViewById(R.id.coordinateText);
imageView.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
String text = " x = " + motionEvent.getX() + " and y = " + motionEvent.getY();
// Log.d("Tag", "X,Y : " + motionEvent.getX() + "," + motionEvent.getY());
coordinateText.setText(text);
return true;
}
});
}
activity_main.xml is:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="saleskit.orbitsys.com.damagemarkingdemo.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/coordinateText"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView"
android:src="#drawable/superb_dm_left_v01"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

Android onTouch and coordinates

I have this XML wherein I have a Relative layout and a button
XML Code:
<RelativeLayout
android:layout_width="500dp"
android:layout_height="250dp"
>
<Button
android:id="#+id/triggerButton"
android:layout_width="45dp"
android:layout_height="45dp"
android:background="#color/colorAccent"
android:layout_marginTop="94dp"
android:layout_alignParentTop="true"
android:layout_weight="0.5"
android:keepScreenOn="false" />
<RelativeLayout
android:layout_width="500dp"
android:layout_height="250dp"
android:id="#+id/relativeLayout_Touch"
android:background="#android:color/holo_green_light"
android:elevation="2dp">
</RelativeLayout>
Also, I have this code to get the coordinates of the onClick and a code to get the coordinates of the button.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
point.x = event.getX();
point.y = event.getY();
String message = point.x + " " + point.y
int[] test = new int[2];
btTrigger.getLocationOnScreen(test);
String message2 = "X: " + test[0] + "," + "Y: " + test[1];
Log.e("COORDINATE", message);
Log.e("BUTTON COORDINATE", message2);
}
invalidate();
return true;
}
How can I check if I clicked the position of the button, without clicking the button itself. (which I can't click because the RelativeLayout is infront of the button.)
It needs to be in front of the button because whenever the user clicks the relativelayout will have a red circle.
canvas.drawCircle(point.x, point.y, 100, paint);
I have 2 options in my mind, tho idk if it's possible:
Increase the size of the click to adjust to the button size?
Or try to merge(?) the button and the relativelayout. (Whenever i click the button the drawing of circle will still appear.

Drag & Drop does not work properly with embedded EditText on Android API 24

I have an app and it has been working well. However, after I upgraded the phone to Android 7.0, the drag and drop function was broken. And if I further upgrade the phone to Android 7.1, it works well again.
And then I created a test app to find out the cause, but I can only "prove" that it has something to do with the nested EditText inside a RelativeLayout.
Here is the code to show the log:
private class EntryHolder{
View mEntryLayout;
View mEntryContainer;
}
void addView() {
EntryHolder eh = new EntryHolder();
eh.mEntryLayout = getLayoutInflater()
.inflate(R.layout.edit_item, mContainer, false);
eh.mEntryContainer = eh.mEntryLayout.findViewById(R.id.field_container);
eh.mEntryContainer.setTag(eh);
eh.mEntryLayout.setTag(eh);
mContainer.addView(eh.mEntryLayout, mIndex++);
eh.mEntryContainer.setOnLongClickListener(this);
eh.mEntryLayout.setOnDragListener(mDragListener);
}
private class DragListener implements View.OnDragListener {
String[] ACTIONS = {"---", "STARTED ", "LOCATION ", "DROP ",
"ENDED ", "ENTERED ", "EXITED "};
#Override
public boolean onDrag(View view, DragEvent dragEvent) {
int action = dragEvent.getAction();
Log.d("Drag&Drop", ACTIONS[action]+view.toString());
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
case DragEvent.ACTION_DRAG_ENTERED:
case DragEvent.ACTION_DRAG_ENDED:
case DragEvent.ACTION_DRAG_LOCATION:
case DragEvent.ACTION_DROP:
return true;
}
return false;
}
#Override
public boolean onLongClick(View view) {
ClipData not_used_clip = ClipData.newPlainText("", "");
EntryHolder eh = (EntryHolder)view.getTag();
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
eh.mEntryLayout.startDrag(not_used_clip, new View.DragShadowBuilder(eh.mEntryLayout),
eh.mEntryLayout, 0);
}
else {
eh.mEntryLayout.startDragAndDrop(not_used_clip, new View.DragShadowBuilder(eh.mEntryLayout),
eh.mEntryLayout, 0);
}
view.setAlpha(0.0f);
return true;
}
in onCreateView method of the test activity, addView is called 3 times to dynamically add 3 of the frame_layout.
If I put the frame_layout xml this way:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:elevation="8dp">
<RelativeLayout android:id="#+id/field_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:longClickable="true"
android:background="#android:color/holo_blue_bright">
<LinearLayout android:id="#+id/line1"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="36dp">
<!--Something is supposed to be here-->
</LinearLayout>
<EditText
android:id="#+id/field_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Value"
android:layout_below="#id/line1"
android:textAppearance="#style/TextAppearance.AppCompat.Body2"/>
</RelativeLayout>
</FrameLayout>
The output in logcat would simply be the following in Android API 24,
...D/Drag&Drop: STARTED android.widget.FrameLayout{63144b4 ...
...D/Drag&Drop: STARTED android.widget.FrameLayout{231eb23 ...
...D/Drag&Drop: STARTED android.widget.FrameLayout{d141b9e ...
...D/Drag&Drop: ENDED android.widget.FrameLayout{63144b4 ...
...D/Drag&Drop: ENDED android.widget.FrameLayout{d141b9e ...
...D/Drag&Drop: ENDED android.widget.FrameLayout{231eb23 ...
In other versions (including API 23- and API 25), the output would be much more with ENTERED, LOCATION and EXITED
If I remove the RelativeLayout in the middle or if I remove the EditText, then it is fine in API 24 as well. But I need that level of layout in my actual app so I cannot solve it this way.
Can anybody have any suggestions on the problem? Thank you!

Click ImageView on Specific Location

I have an imageView and when I need to let the user click only on a specific location (the white space) as shown in the image below, any suggestion?
here is my xml
<RelativeLayout
android:id="#+id/lockRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="5dp"
>
<ImageView
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/image" />
</RelativeLayout>
and here is the code
private View.OnTouchListener imageViewOnClickListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN){
//here i want if he clicked on specific location to go to another activity
Intent intent = new Intent(context, ViewerActivity.class);
context.startActivity(intent);
}
return true;
}
};
I don't know if i should use onClick or onTouchClick!!
You could implement the OnTouchListener.
anImageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
//Check between +- 10px jsu tto have some are to hit
int centerX = (v.getWidth() /2);
if(event.getX() > centerX - 10)
&& event.getX() < centerX + 10)){
//Do your magic
}
}
return true;
}
});
The event contains the coordinates for the event.
Then you can compare that either to the the boundaries you set up or get the correct pixel from the image an check if it is white.
I would advise to put another transparent control in your relative layout on top of ImageView with paddings you need, and subscribe to its onClick event. This way you can be sure only proper area was clicked.
What i did is I used two images One for Show your Image and Secound is show only Some Part of that where you want to click
Please Note My Secound Image is my transparent image. So use one1 as a transparent image. And use its Click Event.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/ic_launcher" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#xml/shape"
android:gravity="center" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/one1" />
</LinearLayout>
now create xml and create shape.xml file which is give to Linearlayout
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="20dip" />
<stroke
android:width="100dip"
android:color="#A0ffffff" />
i found a solution by myself: thanks all for replying:
private View.OnTouchListener imageViewOnClickListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int x = (int) event.getX();
if (173 <= x && x <= 671) {
Intent intent = new Intent(context, NextActivity.class);
context.startActivity(intent);
}
return true;
}
};

Why my animation does not stop in the to-x given value?

I want to move a view on touch and when the user unholds this view, it is started an animation which moves my view to the end of its parent.
This is my layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/time_view"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<AbsoluteLayout
android:id="#+id/slide_layout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_margin="20dp"
android:background="#0000FF" >
<View
android:id="#+id/slide_to_pause"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="#00FFFF" />
</AbsoluteLayout>
</RelativeLayout>
This is how I set the view to move in my onCreate:
slideView = ((View) findViewById(R.id.slide_to_pause));
slideView.setOnTouchListener(this);
This is how I move the view and starts the animation:
#Override
public boolean onTouch(View view, MotionEvent event) {
AbsoluteLayout.LayoutParams layoutParams = (AbsoluteLayout.LayoutParams) view.getLayoutParams();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mX = event.getRawX();
break;
case MotionEvent.ACTION_UP:
int endOfAnimation = findViewById(R.id.slide_layout).getWidth() - view.getWidth();
mSlideAnimation = new TranslateAnimation(0, endOfAnimation - layoutParams.x, 0, 0);
mSlideAnimation.setDuration(1000);
view.startAnimation(mSlideAnimation);
Log.d(TAG, "endOfAnimation = " + layoutParams.x + " | " + endOfAnimation);
break;
case MotionEvent.ACTION_MOVE:
layoutParams.x = (int) event.getRawX();
view.setLayoutParams(layoutParams);
break;
}
return true;
}
The problem is that when the view arrives at the end it comes back to a point in the midle of the screen, which is the point where the user unholds the view.
How can I fix this?
Thank you!
You need to use
mSlideAnimation.setFillAfter(true);
to make it not revert back to the start.
If that doesn't work you might have to follow the suggestion on Animation.setFillAfter/Before - Do they work/What are they for?
You can simulate animation manually (move views yourself, without animation framework) by using
View.offsetLeftAndRight(int offset)
View.offsetTopAndBottom(int offset)

Categories

Resources