Can't see click ripple effect in Android Touch events
Asked Answered
B

3

7

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>
Binate answered 13/4, 2020 at 15:6 Comment(2)
Please share your layout code as well.Andromache
Please see update 2 above. I've added android:background="?android:attr/selectableItemBackground" android:focusable="true" android:clickable="true" in the root view.Binate
B
18

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);
                            }
                        }
Binate answered 14/4, 2020 at 0:49 Comment(1)
worth noting that there is also MotionEvent.ACTION_CANCEL and it may occur INSTEAD ACTION_UP, so in that case setPressed(false) should also be calledQuaker
A
1

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>
Andromache answered 13/4, 2020 at 16:12 Comment(2)
Thanks for the answer, but I have also tried this before, and it didn't work either. Tried both background and foreground. Is there a way to create it directly inside the onTouch method?Binate
I don't know. You can try that. @VinitShandilyaAndromache
K
0

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" />
Kittie answered 13/4, 2020 at 15:12 Comment(4)
I've tried this, but it doesn't work for me. I believe the attributes will work only for onclicklistener.Binate
have you try to wrap your view as children and set the parent view's background to selectableItemBackground ?. see other references: https://mcmap.net/q/1476225/-no-ripple-effect-on-recycleview-touch-event, https://mcmap.net/q/1476226/-recycler-view-item-it-is-not-showing-ripple-effect-touch-highlight-i-applied-listener-by-using-gesture-detractorKittie
Yes, tried that as well. The point is, the gesture call is not getting to onclick event, which actually displays the ripple effect.Binate
You right if you use onClickListener but doesn´t work if you use gesture detectorAramenta

© 2022 - 2024 — McMap. All rights reserved.