【问题标题】:How to prevent ListView scrolling while touching/swiping/fling its row?如何在触摸/滑动/翻转其行时防止 ListView 滚动?
【发布时间】:2013-07-09 21:45:30
【问题描述】:

如果在某些特定 ListView 的行中做出这些手势,我需要停止 ListView 以响应用户手势 - 怎么做?目标 ListView 的行视图设置了 onTouchListener,由于 ListView 向上/向下滚动,我无法识别滑动/翻转。因此,如果我将手指向上或向下移动一点 - ListView 会拦截它并沿相应的方向滚动。所以我需要以某种方式来控制它,就像 Y 坐标变化超过一定数量 - 让 ListView 滚动,如果没有 - 将手势识别为投掷/滑动。 OnTouchListener 是

private int SWIPE_MIN_DISTANCE = 1;
private int SWIPE_MAX_OFF_PATH = 300;

final OnTouchListener flingSwipeListener =  new OnTouchListener() {
    float touchX;
    float touchY;
    @Override
    public boolean onTouch(final View view, final MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN)
        {
            touchX = event.getX();
            touchY = event.getY();
        }
        else if (event.getAction() == MotionEvent.ACTION_UP)
        {                   
        if (Math.abs(touchY - event.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;
            // right to left swipe
            else if (touchX - event.getX() > SWIPE_MIN_DISTANCE){
                    Log.i("flingSwipe","right to left swipe");
            } 
            // left to right swipe
            else if (event.getX() - touchX > SWIPE_MIN_DISTANCE){
                    Log.i("flingSwipe","left to right swipe");
            }
        }
        return true;

    }
};

这个 onTouchListner 被设置为一个特定的行。我需要在 onTouchListener 识别手势时冻结 ListView,但如果失败,我需要将 MotionEvent 发送到 ListView。

【问题讨论】:

    标签: android listview gesture


    【解决方案1】:

    如果您需要在特定行上禁用触摸侦听器。比这更简单。

    在所需的列表行上设置标签。在 getview 列表适配器类中。

    例如:

    ABCList extends ArrayAdapter<String> {
            public MyCustomAdapter(Context context, int textViewResourceId,
                    String[] objects) {
                super(context, textViewResourceId, objects);
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
    
                View row = inflater.inflate(R.layout.history_list_item, parent,
                        false);
    
                if(position == YOUR_DESIRED_ROW)
                              row.setTag("disableThisRow")
    
                return row;
            }
    
    
        }
    

    然后像这样编辑触摸监听器。

     final OnTouchListener flingSwipeListener =  new OnTouchListener() {
        float touchX;
        float touchY;
        @Override
        public boolean onTouch(final View view, final MotionEvent event) {
           String isRow=view.getTag();
           if(isRow.equals("disableThisRow"))return false;
    
            if (event.getAction() == MotionEvent.ACTION_DOWN)
            {
                touchX = event.getX();
                touchY = event.getY();
            }
            else if (event.getAction() == MotionEvent.ACTION_UP)
            {                   
            if (Math.abs(touchY - event.getY()) > SWIPE_MAX_OFF_PATH)
                        return false;
                // right to left swipe
                else if (touchX - event.getX() > SWIPE_MIN_DISTANCE){
                        Log.i("flingSwipe","right to left swipe");
                } 
                // left to right swipe
                else if (event.getX() - touchX > SWIPE_MIN_DISTANCE){
                        Log.i("flingSwipe","left to right swipe");
                }
            }
    
            return true;
    
        }
    };
    

    这将禁用不想要的列表项的触摸..希望这会有所帮助。 或者,如果您的手势监听器比这更多,也将与此类似。 希望对你有帮助

    【讨论】:

    • 不,如果我滑动它的特定行,我需要禁用 ListView 的内置触摸检测器/识别器。因为我需要在滑动其行时冻结 ListView。
    • 好的,你必须做的是每当用户触摸你想要的行。而不是禁用列表滚动。不是吗?当用户触摸其他行时,启用默认滚动。
    • 是的,就像我在问题的代码下方添加的一样。当用户在特定 ListView 的行中做出手势时,我需要冻结 ListView。所有其他 ListView 的行必须照常运行。此外,当我检测到 OnTouchListener 中的 Y 轴移动太大时,我需要将手势转移到 ListView,以使用户即使通过我的特殊行也能够滚动 ListView。
    【解决方案2】:

    如果您想在检测到任何水平滚动(滑动)时禁用 ListView 的垂直滚动,请使用以下解决方案 - 在您的自定义 ListView 类中覆盖 onTouchEvent 并将动作 MotionEvent.ACTION_MOVE 替换为 MotionEvent.ACTION_CANCEL:

    public class ListView2 extends ListView
    {
        private enum ScrollDirection
        {
            Horizontal,
            Vertical
        }
    
        private final int touchSlop;
    
        private float downX = 0;
        private float downY = 0;
    
        private ScrollDirection scrollDirection;
    
        public ListView2(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent ev)
        {
            switch (ev.getActionMasked())
            {
                case MotionEvent.ACTION_MOVE:
                    if (scrollDirection == null)
                    {
                        if (Math.abs(downX - ev.getX()) > touchSlop) scrollDirection = ScrollDirection.Horizontal;
                        else if (Math.abs(downY - ev.getY()) > touchSlop) scrollDirection = ScrollDirection.Vertical;
                    }
                    if (scrollDirection == ScrollDirection.Horizontal) ev.setAction(MotionEvent.ACTION_CANCEL);
                    break;
    
                case MotionEvent.ACTION_DOWN:
                    scrollDirection = null;
                    downX = ev.getX();
                    downY = ev.getY();
                    break;
    
            }
            return super.onTouchEvent(ev);
        }
    }
    

    当然你可以让检查逻辑是否禁用垂直滚动更复杂。

    【讨论】:

      猜你喜欢
      • 2011-10-27
      • 1970-01-01
      • 2014-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多