这是我的old question。不过这次我也提供了我的代码。
我有一个包含不同类型行的ListView。该行可能包含文本,图像,视频或其他内容。如果我点击ImageView(在行内)我将转到另一个活动以全屏显示图像,如果我点击视频(在行内),我将转到另一个活动来播放他的视频。
我在ListView上实现了从右到左的滑动侦听器。如果我从ListView中的空白区域启动ListView滑动,则滑动工作(下图中的第一行和第二行)。但是,如果我从ListView行的项目开始ListView滑动,则滑动不起作用(下图中的第三和第四行)。如果我从ImageView和Video中删除了单击事件,那么即使我从ListView行的项目开始滑动,滑动仍然有效,即在这种情况下滑动适用于整个ListView,无论我在哪一行进行滑动。
我怎样摆脱这个问题?我想如果我禁用ListView中所有项目的所有点击事件,就可以实现这一点。怎么会这样?还有其他办法吗?
我想要在ListView上滑动并单击ListView的项目。
SwipeDetector.java - 用于检测ListView上的滑动
public class SwipeDetector implements View.OnTouchListener {
private SwipeListener swipeListener;
private ListView mListView;
private int hundred;
private boolean motionInterceptDisallowed = false;
public static enum Action {
LR, // Left to right
RL, // Right to left
TB, // Top to bottom
BT, // Bottom to top
None // Action not found
}
private static final int HORIZONTAL_MIN_DISTANCE = 30; // The minimum
// distance for
// horizontal swipe
private static final int VERTICAL_MIN_DISTANCE = 80; // The minimum distance
// for vertical
// swipe
private float downX, downY, upX, upY; // Coordinates
private Action mSwipeDetected = Action.None; // Last action
public SwipeDetector(Context context, ListView listView) {
hundred = (int) context.getResources().getDimension(R.dimen.hundred);
mListView = listView;
}
public boolean swipeDetected() {
return mSwipeDetected != Action.None;
}
public Action getAction() {
return mSwipeDetected;
}
/**
* Swipe detection
*/@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
{
downX = event.getX();
downY = event.getY();
mSwipeDetected = Action.None;
return false; // allow other events like Click to be processed
}
case MotionEvent.ACTION_MOVE:
{
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
float absX = Math.abs(deltaX);
float absY = Math.abs(deltaY);
if((absX >= (3 * absY)) && absX > HORIZONTAL_MIN_DISTANCE && mListView != null && !motionInterceptDisallowed) {
mListView.requestDisallowInterceptTouchEvent(true);
motionInterceptDisallowed = true;
}
if((absX >= (3 * absY)) && absX <= hundred) {
if (deltaX > 0) {
mSwipeDetected = Action.RL;
swipeListener.onSwipe(MotionEvent.ACTION_MOVE, Action.RL, absX);
}
}
return false;
}
case MotionEvent.ACTION_UP:
swipeListener.onSwipe(MotionEvent.ACTION_UP, Action.BT, 0);
if (mListView != null) {
mListView.requestDisallowInterceptTouchEvent(false);
motionInterceptDisallowed = false;
}
return false;
case MotionEvent.ACTION_CANCEL:
return true;
}
return false;
}
/**
* Set chat send listener
* @param listener
*/
public void setSwipeListener(SwipeListener listener) {
swipeListener = listener;
}
public interface SwipeListener {
void onSwipe(int event, Action action, float x);
}
}
这就是我在ListView上设置SwipeDetector的方法
final SwipeDetector swipeDetector = new SwipeDetector(SwipeActivity.this, mListView);
swipeDetector.setSwipeListener(mSwipeListener);
mListView.setOnTouchListener(swipeDetector);
我的活动实施SwipeDetector.SwipeListener
下面是onSwipe()方法
@Override
public void onSwipe(int event, SwipeDetector.Action action, float x) {
switch (event) {
case MotionEvent.ACTION_MOVE:
System.out.println("list move");
break;
case MotionEvent.ACTION_UP:
System.out.println("list up");
break;
}
}
在我的适配器中,我在TextView,ImageView和VideoView上设置onClickListener()
holder.mTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("item textview click");
}
});
holder.mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("item imageview click");
}
});
holder.mVideoView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("item videoview click");
}
});
当我从ListView的空白区域开始滑动时,ListView的滑动侦听器会捕获它。但是,当我从TextView / ImageView / VideoView开始滑动时,会触发View的onClickListener,而不是父类(ListView的)onTouchListener()。
我该如何实现?我希望当我单击ListView的项目时,该项目的onClick应该被触发,当我在ListView的项目上滑动时,ListView的onSwipe应该被解雇。
答案 0 :(得分:1)
onClickListener
listitem
和SwipeListener
List
都不可能,因为它在触摸时要考虑的视图之间存在歧义
您使用实现OnSwipeTouchListener
onTouchListener
<强> OnSwipeTouchListener.java 强>
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
result = true;
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}
result = true;
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
public void onSwipeTop() {
}
public void onSwipeBottom() {
}
}
在OnSwipeTouchListener
listitem
listitem.setOnTouchListener(new OnSwipeTouchListener() {
public void onSwipeLeft() {
//stuff to do list view left swipe
Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}
public boolean onTouch(View v, MotionEvent event) {
//stuff to do on list item click
return gestureDetector.onTouchEvent(event);
}
});
}); //to get click events
答案 1 :(得分:0)
我知道这是一个老问题,但是今后搜索仍然是一个更好的解决方案:
尝试使用RecyclerView而不是ListView,并添加recyclerview项目的OnItemTouchListener。
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(
this,
new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// Your code here for item on click event...
}
},
runnableSwipeLeftToRight,
runnableSwipeRightToLeft)
);
以下两种方法将在适当的滑动上执行:
Runnable runnableSwipeRightToLeft = new Runnable() {
public void run() {
// Your Code here...
}
};
Runnable runnableSwipeLeftToRight = new Runnable() {
public void run() {
// Your code here...
}
};
这是触摸和滑动检测的类代码:
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener, RecyclerView.OnLongClickListener {
private OnItemClickListener mListener;
GestureDetector gestureDetector;
Runnable runnableSwipeLeftToRight, runnableSwipeRightToLeft;
private static final String TAG = "RecyclerItemClickListen";
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 200;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
@Override
public boolean onLongClick(View view) {
return false;
}
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener, Runnable runnableSwipeLeftToRight, Runnable runnableSwipeRightToLeft) {
this.mListener = listener;
this.runnableSwipeLeftToRight = runnableSwipeLeftToRight;
this.runnableSwipeRightToLeft = runnableSwipeRightToLeft;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
gestureDetector = new GestureDetector(context, new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) { }
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) { return false; }
@Override
public void onLongPress(MotionEvent motionEvent) { }
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float v1) {
try {
float diffAbs = Math.abs(e1.getY() - e2.getY());
float diff = e1.getX() - e2.getX();
if (diffAbs > SWIPE_MAX_OFF_PATH) {
return false;
}
// Left swipe
if (diff > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
onLeftSwipe();
// Right swipe
} else if (-diff > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
onRightSwipe();
}
} catch (Exception e) {
Log.e("YourActivity", "Error on gestures");
}
return false;
}
});
}
private void onLeftSwipe() {
Log.d(TAG, "onLeftSwipe: ");
runnableSwipeRightToLeft.run();
}
private void onRightSwipe() {
Log.d(TAG, "onRightSwipe:");
runnableSwipeLeftToRight.run();
}
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
View childView = view.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
}
return gestureDetector.onTouchEvent(e);
}
@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
希望这会对你有所帮助。