ListView上的SwipeListener和ListView项目上的ClickListener

时间:2015-09-30 12:39:42

标签: android android-listview swipe

这是我的old question。不过这次我也提供了我的代码。

我有一个包含不同类型行的ListView。该行可能包含文本,图像,视频或其他内容。如果我点击ImageView(在行内)我将转到另一个活动以全屏显示图像,如果我点击视频(在行内),我将转到另一个活动来播放他的视频。

我在ListView上实现了从右到左的滑动侦听器。如果我从ListView中的空白区域启动ListView滑动,则滑动工作(下图中的第一行和第二行)。但是,如果我从ListView行的项目开始ListView滑动,则滑动不起作用(下图中的第三和第四行)。如果我从ImageView和Video中删除了单击事件,那么即使我从ListView行的项目开始滑动,滑动仍然有效,即在这种情况下滑动适用于整个ListView,无论我在哪一行进行滑动。

enter image description here

我怎样摆脱这个问题?我想如果我禁用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应该被解雇。

2 个答案:

答案 0 :(得分:1)

onClickListener listitemSwipeListener 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) {

}

}

希望这会对你有所帮助。