【问题标题】:How to handle both OnTouchListener event and OnClickListener event如何同时处理 OnTouchListener 事件和 OnClickListener 事件
【发布时间】:2020-09-09 12:36:25
【问题描述】:

我有RecyclerView 并设置了OnTouchListenerOnClickListener 的每个项目

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:(在视图持有者内)

 init {
    itemView.setOnClickListener(this)
}

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

问题是当我点击该项目时,只触发了startDragListener,但从未触发过点击事件。

我在 stackoverflow 上阅读了一些关于此问题的类似问题,但其中大多数都是非常旧/不推荐使用的方法

如何解决这个问题并同时处理触摸监听器和点击监听器?

【问题讨论】:

    标签: android kotlin android-recyclerview listener


    【解决方案1】:

    看,onClickListener 不能与 onTouchListener 一起使用。您必须实现一些逻辑来区分 onTouchListener 中的单击和拖动。我做了这样的事情,代码在java中,但你可以得到一个想法。

    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;
    
        }
    

    【讨论】:

    • 我不认为这是正确/最好的方法,但它确实有效!只是一个小问题:为什么当我点击项目时ACTION_UPACTION_DOWN 都被调用,但是当我移动项目时只有ACTION_DOWN 被调用(当然还有onMove)?
    • 如果您的 ACTION_MOVE 案例返回 true,那么仍然会调用 ACTION_UP。如果您不想在 ACTION_MOVE 之后调用 ACTION_UP,请不要返回 true。我希望它能澄清你的问题。
    【解决方案2】:

    您需要实现一个GestureListener 来拦截点击事件和其他手势事件。

    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 () {
    
    }
    }
    

    然后:

    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);
            }
        });
    

    您可以根据需要为MyGestureListener类添加更多方法。

    【讨论】:

      【解决方案3】:

      将您的 onClickListener 代码更改为:

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

      【讨论】:

        猜你喜欢
        • 2011-11-01
        • 2021-03-05
        • 1970-01-01
        • 2011-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-12
        • 1970-01-01
        相关资源
        最近更新 更多