嵌套的 RecyclerView.如何防止父 RecyclerView 在子 RecyclerView 滚动时滚动? [英] Nested RecyclerView. How to prevent parent RecyclerView from getting scrolled while child RecyclerView is scrolling?

查看:23
本文介绍了嵌套的 RecyclerView.如何防止父 RecyclerView 在子 RecyclerView 滚动时滚动?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个水平的 recyclerview,并且 recyclerview 的每一项都将是一个具有网格布局的垂直 recyclerview.我面临的问题是,当我尝试垂直滚动子 recyclerview 时,有时父 recyclerview 接受滚动并开始水平滚动.我试图解决这个问题的方法是,

  1. setNestedScrollingEnabled(false) 在父 recyclerview
  2. 在子recyclerviewonTouch() 中,我通过调用requestdisallowinterceptTouchevent(false) 禁用了父recyclerview 上的触摸事件

以上解决方案均无法完美解决问题.任何帮助表示赞赏

解决方案

我觉得这个问题很有趣.所以我尝试实施,这就是我取得的成果(您也可以在

所以你可以尝试这样的事情:

定义 CustomLinearLayoutManager 扩展 LinearLayoutManager 像这样:

public class CustomLinearLayoutManager extends LinearLayoutManager {公共 CustomLinearLayoutManager(上下文上下文,整数方向,布尔反向布局){超级(上下文,方向,reverseLayout);}@覆盖公共布尔 canScrollVertically() {返回假;}}

并将此 CustomLinearLayoutManager 设置为您的父 RecyclerView.

RecyclerView parentRecyclerView = (RecyclerView)findViewById(R.id.parent_rv);CustomLinearLayoutManager customLayoutManager = new CustomLinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false);parentRecyclerView.setLayoutManager(customLayoutManager);parentRecyclerView.setAdapter(new ParentAdapter(this));//一些适配器

现在为子RecyclerView,定义自定义CustomGridLayoutManager 扩展GridLayoutManager:

public class CustomGridLayoutManager extends GridLayoutManager {公共 CustomGridLayoutManager(上下文上下文,AttributeSet attrs,int defStyleAttr,int defStyleRes){超级(上下文,属性,defStyleAttr,defStyleRes);}公共 CustomGridLayoutManager(上下文上下文,int spanCount){超级(上下文,spanCount);}public CustomGridLayoutManager(上下文上下文,int spanCount,int方向,boolean reverseLayout){超级(上下文,spanCount,方向,reverseLayout);}@覆盖公共布尔 canScrollHorizo​​ntally() {返回假;}}

并将其设置为layoutManger给子RecyclerView:

childRecyclerView = (RecyclerView)itemView.findViewById(R.id.child_rv);childRecyclerView.setLayoutManager(new CustomGridLayoutManager(context, 3));childRecyclerView.setAdapter(new ChildAdapter());//一些适配器

所以基本上父 RecyclerView 只听水平滚动,子 RecyclerView 只听垂直滚动.

除此之外,如果您还想处理对角滑动(几乎不偏向垂直或水平),您可以在 parent RecylerView.

public class ParentRecyclerView extends RecyclerView {私有 GestureDetector mGestureDetector;公共 ParentRecyclerView(上下文上下文){超级(上下文);mGestureDetector = new GestureDetector(this.getContext(), new XScrollDetector());//在其他构造函数中做同样的事情}//并覆盖 onInterceptTouchEvent@覆盖公共布尔 onInterceptTouchEvent(MotionEvent ev) {返回 super.onInterceptTouchEvent(ev) &&mGestureDetector.onTouchEvent(ev);}}

XScrollDetector 在哪里

class XScrollDetector extends GestureDetector.SimpleOnGestureListener {@覆盖公共布尔 onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {返回 Math.abs(distanceY) 

因此 ParentRecyclerView 要求子视图(在我们的例子中是 VerticalRecyclerView)来处理滚动事件.如果子视图处理,则父视图不执行其他操作,父视图最终会处理滚动.

I am trying to implement a horizontal recyclerview and each item of the recyclerview will be a vertical recyclerview with a grid layout. The problem that i am facing is that when I try to scroll the child recyclerview vertically sometimes the parent recyclerview takes the scroll and starts scrolling horizontally. The approaches I tried to fix this are,

  1. setNestedScrollingEnabled(false) on the parent recyclerview
  2. In the onTouch() of the child recyclerview I disable touch events on the parent recyclerview by called requestdisallowinterceptTouchevent(false)

None of the above solutions provide a perfect fix for the problem. Any help is appreciated

解决方案

The problem seemed interesting to me. So I tried to implement and this is what I achieved (you can also see the video here) which is pretty smooth.

So you can try something like this:

Define CustomLinearLayoutManager extending LinearLayoutManager like this:

public class CustomLinearLayoutManager extends LinearLayoutManager {

    public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    @Override
    public boolean canScrollVertically() {
        return false;
    }
}

and set this CustomLinearLayoutManager to your parent RecyclerView.

RecyclerView parentRecyclerView = (RecyclerView)findViewById(R.id.parent_rv);
CustomLinearLayoutManager customLayoutManager = new CustomLinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false);
parentRecyclerView.setLayoutManager(customLayoutManager);
parentRecyclerView.setAdapter(new ParentAdapter(this)); // some adapter

Now for child RecyclerView, define custom CustomGridLayoutManager extending GridLayoutManager:

public class CustomGridLayoutManager extends GridLayoutManager {

    public CustomGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public CustomGridLayoutManager(Context context, int spanCount) {
        super(context, spanCount);
    }

    public CustomGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
        super(context, spanCount, orientation, reverseLayout);
    }

    @Override
    public boolean canScrollHorizontally() {
        return false;
    }
}

and set it as layoutManger to the child RecyclerView:

childRecyclerView = (RecyclerView)itemView.findViewById(R.id.child_rv);
childRecyclerView.setLayoutManager(new CustomGridLayoutManager(context, 3));
childRecyclerView.setAdapter(new ChildAdapter()); // some adapter

So basically parent RecyclerView is only listening to horizontal scrolls and child RecyclerView is only listening to vertical scrolls.

Along with that, if you also want to handle diagonal swipe (which is little skewed to either vertical or horizontal), you can include a gesture listener in the parent RecylerView.

public class ParentRecyclerView extends RecyclerView {

    private GestureDetector mGestureDetector;

    public ParentRecyclerView(Context context) {
        super(context);
        mGestureDetector = new GestureDetector(this.getContext(), new XScrollDetector());
       // do the same in other constructors
    }

   // and override onInterceptTouchEvent

   @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev) && mGestureDetector.onTouchEvent(ev);
    }

}

Where XScrollDetector is

class XScrollDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            return Math.abs(distanceY) < Math.abs(distanceX);
        }
}

Thus ParentRecyclerView asks child view (in our case, VerticalRecyclerView) to handle the scroll event. If the child view handles then parent does nothing else parent eventually handles the scroll.

这篇关于嵌套的 RecyclerView.如何防止父 RecyclerView 在子 RecyclerView 滚动时滚动?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆