androiduser-interfaceontouchlistenerandroid-gesturerippledrawable

Can't see click ripple effect in Android Touch events


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>

Solution

  • 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);
                                }
                            }