SwipeRefreshLayout中的Horizo​​ntalScrollView

Lio*_*luz 50 android horizontalscrollview swiperefreshlayout

我实现了新的SwipeRefreshLayout成分在我的应用程序,它与任何垂直意见工作得很好,比如ListView,GridViewScrollView.

它在水平视图中表现得很糟糕,比如HorizontalScrollView.向右或向左滚动时,SwipeRefreshLayout视图会缓存触摸,阻止HorizontalScrollView接收并开始垂直滚动以执行刷新.

我尝试解决这个问题,因为我之前解决了ScrollViewViewPager内部垂直问题,使用requestDisallowInterceptTouchEvent但它没有用.我还注意到,在原始SwipeRefreshLayout类中重写此方法而不返回super.谷歌的开发者留下了评论" //Nope.":)

因为SwipeRefreshLayout组件相对较新,我找不到修复水平滚动问题的解决方案,同时仍然允许滑动刷新视图以跟踪和处理垂直滚动,所以我想我会分享我的解决方案,希望它会让人节省一个小时或两个.

Lio*_*luz 147

我通过扩展SwipeRefreshLayout和覆盖它来解决它onInterceptTouchEvent.在里面,我计算用户徘徊的X距离是否大于触摸坡度.如果是,则表示用户正在水平滑动,因此我返回false,让孩子查看(HorizontalScrollView在这种情况下)获取触摸事件.


public class CustomSwipeToRefresh extends SwipeRefreshLayout {

    private int mTouchSlop;
    private float mPrevX;

    public CustomSwipeToRefresh(Context context, AttributeSet attrs) {
        super(context, attrs);

        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPrevX = MotionEvent.obtain(event).getX();
                break;

            case MotionEvent.ACTION_MOVE:
                final float eventX = event.getX();
                float xDiff = Math.abs(eventX - mPrevX);

                if (xDiff > mTouchSlop) {
                    return false;
                }
        }

        return super.onInterceptTouchEvent(event);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 多么华丽的解决方案!! 你救了我一天!! 谢谢 :) (10认同)
  • 惊人.谢谢你的解决方案!我可能永远都不会想到这一点.您只需要删除自定义小部件来代替xml文件中的原始滑动刷新布局,它就可以工作了!这可能应该修补到Android源代码! (7认同)
  • 你是我的英雄! (2认同)

Twi*_*bit 27

如果您没有记住已经拒绝了ACTION_MOVE事件的事实,那么如果用户返回到您的初始mPrevX附近,您最终会在以后使用它.

只需添加一个布尔值来记住它.

public class CustomSwipeToRefresh extends SwipeRefreshLayout {

    private int mTouchSlop;
    private float mPrevX;
    // Indicate if we've already declined the move event
    private boolean mDeclined;

    public CustomSwipeToRefresh(Context context, AttributeSet attrs) {
        super(context, attrs);

        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mPrevX = MotionEvent.obtain(event).getX();
                mDeclined = false; // New action
                break;

            case MotionEvent.ACTION_MOVE:
                final float eventX = event.getX();
                float xDiff = Math.abs(eventX - mPrevX);

                if (mDeclined || xDiff > mTouchSlop) {
                    mDeclined = true; // Memorize
                    return false;
                }
        }

        return super.onInterceptTouchEvent(event);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 当您开始水平拖动视图并返回到起点时会发生这种情况.当你回来时,你会发现这件事.一种简单的再现方法是向左拖动,向下拖动并向右拖动. (3认同)
  • 为什么不直接使用mPrevX = event.getX(); 而不是mPrevX = MotionEvent.obtain(event).getX(); ?MotionEvent.obtain(event)将创建一个需要回收的运动事件,除非引起内存泄漏. (3认同)