ScrapeW
ScrapeW

Reputation: 529

How to handle both OnTouchListener event and OnClickListener event

I have RecyclerView and I set to each item OnTouchListener and OnClickListener

OnTouchListener:

override fun onBindViewHolder(holder: ItemListViewHolder, position: Int) {
    val item = getItem(position)
    holder.bind(item)
    holder.itemView.cardview.setOnTouchListener { v, event ->
        if (event.action == MotionEvent.ACTION_DOWN) {
            Log.d(TAG, "onBindViewHolder: $event.buttonState")
            this.startDragListener.onStartDrag(holder)
        }
        return@setOnTouchListener true
    }
}

OnClickListener:(inside the view holder)

 init {
    itemView.setOnClickListener(this)
}

 override fun onClick(v: View?) {
        onItemClickListener.onItemClick(adapterPosition)
    }

The problem is when I click on the item, only the startDragListener triggered, but the on click event never triggered.

I read some similar question on stackoverflow about this problem, but most of them are very old/deprecated method

How can I solve this problem and handle both touch listeners and click listeners?

Upvotes: 5

Views: 2947

Answers (3)

sajjad
sajjad

Reputation: 847

What you need is implement a GestureListener to intercept both click events and other gesture events.

public class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;

@Override
public boolean onDown(MotionEvent event) {
    // don't return false here or else none of the other
    // gestures will work
    return true;
}

@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
    onClick();
    return true;
}

@Override
public void onLongPress(MotionEvent e) {

}

@Override
public boolean onDoubleTap(MotionEvent e) {

    return true;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

    return true;
}

@Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
    float diffX = event2.getX() - event1.getX();
    float diffY = event2.getY() - event1.getY();
    if (Math.abs(diffX)<Math.abs(diffY)) {
        if (Math.abs(diffY)>SWIPE_THRESHOLD && Math.abs(velocityY)>SWIPE_VELOCITY_THRESHOLD) {
            float y2 = event2.getY();
            float y1 = event1.getY();
            if (y2>y1) {
                onSwipeDown();
            } else {
                onSwipeUp();
            }
        }
    }
    return true;
}


public void onClick () {

}

public void onSwipeDown () {

}

public void onSwipeUp () {

}
}

And then:

final GestureDetector mDetector = new GestureDetector(getActivity(), new MyGestureListener() {
        public void onClick() {
            manageTopBar();
        }

        public void onSwipeDown() {
            expandChampion();
        }

        public void onSwipeUp() {
            collapseChampion();
        }
    });

    myView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            return mDetector.onTouchEvent(motionEvent);
        }
    });

You can add more methods to MyGestureListener class according to your needs.

Upvotes: 1

Bilal Aslam
Bilal Aslam

Reputation: 839

See, onClickListener won't work with onTouchListener. You will have to implement some logic to differentiate between click and drag in onTouchListener. I did something like this, code is in java but you can get an idea.

switch (motionEvent.getAction()) {
        case MotionEvent.ACTION_DOWN:
            x = motionEvent.getX();
            y = motionEvent.getY();
            return true;

        case MotionEvent.ACTION_UP:
            // PUT ON CLICK LOGIC HERE
            break;
        case MotionEvent.ACTION_MOVE:
            if ((motionEvent.getX() - x) > 80 || (x - motionEvent.getX()) > 80
                    || (motionEvent.getY() - y) > 50 || (y - motionEvent.getY()) > 60) {
                    view.startDrag(data, new View.DragShadowBuilder(view) {
                        @Override
                        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
                            shadowSize.set(view.getWidth(), view.getHeight());
                            shadowTouchPoint.set((int) motionEvent.getX(), (int) motionEvent.getY());
                        }
                    }, view, 0);
            }
            return true;

    }

Upvotes: 4

l_b
l_b

Reputation: 583

Change your onClickListener Code to this:

 itemView.setOnClickListener(object : View.OnClickListener 
    { override fun onClick(v: View) {
     /*do work*/
    } 
    })

Upvotes: 0

Related Questions