Reputation: 529
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
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
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
Reputation: 583
Change your onClickListener Code to this:
itemView.setOnClickListener(object : View.OnClickListener
{ override fun onClick(v: View) {
/*do work*/
}
})
Upvotes: 0