使用PagerSnapHelper

时间:2017-07-27 05:30:22

标签: android android-recyclerview

我正在试图弄清楚实现两个列表的最佳方法是什么,其中父列表可以垂直滑动,子节点可以水平滑动。 假定父列表是无限列表,而子列表最多可以有n个页面。 RecyclerView似乎是最好的工具,并且添加了PagerSnapHelper,重新创建页面滑动行为非常简单(想想ViewPager。) 我面临的当前问题是,当我们一直水平滑动到结束或开始时,有时垂直Recyclerview(父级)接管并更改页面。 即使使用单个垂直回收视图,也可以重新创建,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);

    LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    PagerSnapHelper snapHelper = new PagerSnapHelper();
    SearchAdapter searchAdapter = new SearchAdapter();

    mRecyclerView.setLayoutManager(layoutManager);
    mRecyclerView.setAdapter(searchAdapter);
    snapHelper.attachToRecyclerView(mRecyclerView);
}

从上到下或从下到上滑动/拖动将按预期更改页面。但是,如果您进行水平运动(从左到右或从右到左),有时垂直滑动会启动。 似乎PagerSnapHelper对快速运动非常敏感。当水平启动滑动而不是垂直滑动时,有没有办法避免此页面更改?这个问题在我的案例中更加引人注目,因为我也有一个水平的pagersnaphelper。

可能的解决方案:

  • 扩展RecyclerView控件onTouchEvent和OnInterceptTouchEvent。还没有找到一种方法来使用它。
  • 使用GestureDetector

如果需要,我很乐意提供更多上下文/代码。 拥有两个PagerSnapHelper可能不是Android中的当前模式,但即使我把这部分拿走了,我也想知道为什么PagerSnapHelper对某些手势如此敏感。

2 个答案:

答案 0 :(得分:4)

我认为当父母是垂直的PagerSnapHelpers时,问题是垂直父母将一些水平滑动混淆为垂直。为了避免这种混淆,我拦截了被检测为水平的事件并且禁止父母使用这些事件。 这是我所做的简化版本:

public class VerticalRecyclerView extends RecyclerView {

    private GestureDetector mGestureDetector;

    public VerticalRecyclerView(Context context) {
        super(context);
        init();
    }

    public VerticalRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public VerticalRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        setLayoutManager(layoutManager);

        mGestureDetector = new GestureDetector(getContext(), new HorizontalScrollDetector());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        if (mGestureDetector.onTouchEvent(e)) {
            return false;
        }
        return super.onInterceptTouchEvent(e);
    }

    public class HorizontalScrollDetector extends
            GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return Math.abs(distanceX) > Math.abs(distanceY);
        }

    }
}

它们的关键在于如何检测滚动是否应该被视为水平,如return Math.abs(distanceX) > Math.abs(distanceY);

答案 1 :(得分:0)

apSTRK 在 Kotlin 中的类:


class VerticalRecyclerView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {

    private var mGestureDetector = GestureDetector(context, object : SimpleOnGestureListener() {
        override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float)
            = abs(distanceX) > abs(distanceY)
    })

    override fun onInterceptTouchEvent(e: MotionEvent?) = if (mGestureDetector.onTouchEvent(e)) false
        else super.onInterceptTouchEvent(e)
}