【问题标题】:Vertical and horizontal RecyclerViews with PagerSnapHelper使用 PagerSnapHelper 的垂直和水平 RecyclerViews
【发布时间】:2017-07-27 05:30:22
【问题描述】:

我试图找出实现两个列表的最佳方法,其中父列表可以垂直滑动,子列表可以水平滑动。 假定父列表是一个无限列表,而子列表最多可以有 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 似乎对快速移动非常敏感。当水平而不是垂直启动滑动时,有什么方法可以避免此页面更改?这个问题在我的案例中更为明显,因为我也有一个水平寻呼机。

可能的解决方案:

  • 扩展 RecyclerView 控件 onTouchEvent 和 OnInterceptTouchEvent。还没想出使用这个的方法。
  • 使用 GestureDetector

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

【问题讨论】:

  • 也许你应该覆盖onFling
  • 我也调查过。到触发 onFling 时,方向已经确定,velocityY 小于或大于 0,而 velocityX 始终为 0。我将在我的帖子中添加更多细节。
  • 所以根据 abs(velocity) 你可以返回 super.onFling()false ?
  • 问题是当 onFling 被调用时它总是有垂直速度,这意味着到那时方向已经确定了。我会尝试做的是在 onFling 发生之前禁止触摸。
  • 我现在采用这种方法。我将运动事件从 onInteceptTouchEvent() 传递到自定义 GestureDetector 以获取有关 flings 的更多信息。我注意到,在进行从左到右的运动时,GestureDetector 显示速度velx: -4477.3296 --- velY: 256.26413 和传递给 PagerSnapHelper 的 velY 端。我怎么能确定这不是一个有效的动议?

标签: android android-recyclerview


【解决方案1】:

当必须使用 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);

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
    • 这个答案对 apSTRK 的自我回答有什​​么影响?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-07
    • 2013-12-10
    • 1970-01-01
    • 2014-07-06
    • 2011-11-08
    • 2021-11-08
    相关资源
    最近更新 更多