OnTouchListener 防止视觉反馈

Posted

技术标签:

【中文标题】OnTouchListener 防止视觉反馈【英文标题】:OnTouchListener prevents visual feedback 【发布时间】:2015-10-16 18:15:45 【问题描述】:

我有一个 ListView,它有一个 OnItemClickListener。最重要的是,每一行(CardView)都有一个 OnTouchListener 以实现滑动手势。

OnTouchListener 对 ACTION_DOWN、ACTION_CANCEL、ACTION_MOVE 和 ACTION_UP 做出反应。我在 ACTION_UP 发生时使用 performItemClick(),以便在需要时调用 OnItemClickListener。

如果我在 OnTouchListener 中返回 true,我通过 ACTION_MOVE 实现的滑动动作可以完美运行,单击该项目也可以。 但是,视觉反馈为零。 通常情况下,Lollipop 上会有波纹或 ICS 上的背景变化。

如果我返回 False(意味着我不想拦截该事件),那么会有视觉反馈并且点击有效……但我的 OnTouchListener 永远不会拦截任何 ACTION_MOVE 事件。这可以防止任何滑动。

我尝试了多种解决方案,例如使用 v.setpressed() 但都没有效果。

我很想知道如果我的 OnTouchListener 没有拦截事件,我如何才能保留涟漪(或一般的视觉反馈)。

这是我的 OnTouchListener,如果你好奇的话。

private final View.OnTouchListener mTouchListener = new View.OnTouchListener() 
    float mDownX;
    private int mSwipeSlop = -1;
    private boolean mItemPressed;
    private VelocityTracker mVelocityTracker = null;
    private HashMap<Long, Integer> mItemIdTopMap = new HashMap<>();

    @Override
    public boolean onTouch(final View v, MotionEvent event) 
        int index = event.getActionIndex();
        int pointerId = event.getPointerId(index);

        if (mSwipeSlop < 0) 
            mSwipeSlop = ViewConfiguration.get(getActivity())
                    .getScaledTouchSlop();
        

        switch (event.getAction()) 
            case MotionEvent.ACTION_DOWN:
                if (mItemPressed) 
                    // Multi-item swipes not handled
                    return false;
                
                mItemPressed = true;
                mDownX = event.getX();
                if (mVelocityTracker == null) 
                    // Retrieve a new VelocityTracker object to watch the velocity of a motion.
                    mVelocityTracker = VelocityTracker.obtain();
                 else 
                    // Reset the velocity tracker back to its initial state.
                    mVelocityTracker.clear();
                
                mVelocityTracker.addMovement(event);
                break;
            case MotionEvent.ACTION_CANCEL:
                v.setAlpha(1);
                v.setTranslationX(0);
                mItemPressed = false;
                mVelocityTracker.recycle();
                mVelocityTracker = null;
                break;
            case MotionEvent.ACTION_MOVE: 
                mVelocityTracker.addMovement(event);
                float x = event.getX() + v.getTranslationX();
                float deltaX = x - mDownX;
                float deltaXAbs = Math.abs(deltaX);
                if (!mSwiping) 
                    if (deltaXAbs > mSwipeSlop) 
                        mSwiping = true;
                        getListView().requestDisallowInterceptTouchEvent(true);
                        mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
                    
                
                if (mSwiping) 
                    v.setTranslationX((x - mDownX));
                    v.setAlpha(1 - deltaXAbs / v.getWidth());
                
            
            break;
            case MotionEvent.ACTION_UP: 
                // User let go - figure out whether to animate the view out, or back into place
                if (mSwiping) 
                    float x = event.getX() + v.getTranslationX();
                    float deltaX = x - mDownX;
                    float deltaXAbs = Math.abs(deltaX);
                    float fractionCovered;
                    float endX;
                    float endAlpha;
                    final boolean remove;
                    mVelocityTracker.computeCurrentVelocity(1000);
                    float velocityX = Math.abs(VelocityTrackerCompat.getXVelocity(mVelocityTracker, pointerId));
                    if (velocityX > 700 || deltaXAbs > v.getWidth() / 4) 
                        // fixme
                        fractionCovered = deltaXAbs / v.getWidth();
                        endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
                        endAlpha = 0;
                        remove = true;
                     else 
                        // Not far enough - animate it back
                        fractionCovered = 1 - (deltaXAbs / v.getWidth());
                        endX = 0;
                        endAlpha = 1;
                        remove = false;
                    
                    mVelocityTracker.clear();

                    int SWIPE_DURATION = 600;
                    long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
                    getListView().setEnabled(false);
                    v.animate().setDuration(duration).
                            alpha(endAlpha).translationX(endX).
                            withEndAction(new Runnable()  // fixme replace with AnimationListener
                                @Override
                                public void run() 
                                    // Restore animated values
                                    v.setAlpha(1);
                                    v.setTranslationX(0);
                                    if (remove) 
                                        animateRemoval(getListView(), v);
                                     else 
                                        mBackgroundContainer.hideBackground();
                                        mSwiping = false;
                                        getListView().setEnabled(true);
                                    
                                
                            );
                 else 
                    int position = getListView().getPositionForView(v);
                    if (position != ListView.INVALID_POSITION)
                        getListView().performItemClick(v, position, getListView().getItemIdAtPosition(position));
                
            
            mItemPressed = false;
            break;
            default:
                return false;
        
        return true;
    

    private void animateRemoval(final ListView listview, View viewToRemove) 
        // irrelevant
    
;

它基于几年前 Chet Haase 的 demo。

我真的想不通。帮忙?

谢谢!

【问题讨论】:

可能是***.com/questions/3921138/gesture-in-listview-android? @TudorLuca 手势检测(滑动)工作正常。问题是触摸一行并没有给我任何视觉反馈。 你有没有试过在 ACTION_MOVE 时返回 true,在滑动完成时返回 false? 在你的 switch 案例中 Action_Move 而不是使用 break;删除该行并使用 return false ,试试看 @TudorLuca 我刚试过。诡异:一开始只能滑动(没有点击,没有涟漪),滑动一次之后,变成可以点击(有涟漪),不能滑动。 【参考方案1】:

对我来说,v.setPressed 成功了,其中 v 是接收触摸事件的视图。这意味着在 ACTION_DOWN 上我调用了 v.setPressed(true) 并在 ACTION_UP 上调用了 v.setPressed(false)

【讨论】:

view.setPress() 完美运行,ACTION_UP 时记得设置为 false 【参考方案2】:

我发现导致新片段出现的点击可以防止涟漪。在点击中添加短暂的延迟解决了我的问题。也就是这个

      columnViewHolder.rippleLayout.setOnClickListener((v) -> 

            dataManager.setProducts(id, response.getProducts());
            dataManager.setProductListPosition(id, position);
            dataManager.clearCurrentProductItem();
            Log.d(TAG, "product click " + product.toString());
            EventBus.getDefault().post(new ProductDetailEvent(id, product));
            tagManager.hubSpokeClick(product.getCode());

        );

没有用,但是可以:

           columnViewHolder.rippleLayout.setOnClickListener((v) -> 

                handler.postDelayed(() -> 
                    dataManager.setProducts(id, response.getProducts());
                    dataManager.setProductListPosition(id, position);
                    dataManager.clearCurrentProductItem();
                    Log.d(TAG, "product click " + product.toString());
                    EventBus.getDefault().post(new ProductDetailEvent(id, product));
                    tagManager.hubSpokeClick(product.getCode());
                , 200l);
         );

【讨论】:

以上是关于OnTouchListener 防止视觉反馈的主要内容,如果未能解决你的问题,请参考以下文章

html 断点视觉反馈

如何在 UICollectionView 中启用选择的视觉反馈

智能视觉组赛博 -10赛后反馈

有没有办法降低 HTML5 录制的录制音量以防止反馈?

征集对智能视觉组eIQ的使用反馈

如何通过错误报告反馈链接防止网站攻击?