具有两个RecyclerView的BottomSheetBehavior [英] BottomSheetBehavior with two RecyclerView

查看:452
本文介绍了具有两个RecyclerView的BottomSheetBehavior的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在带有BottomSheetBehavior的LinearLayout中获得了两个RecyclerView.当您单击第一个RecyclerView(带有网格)中的一个项目时,RecyclerView设置为Gone,然后显示第二个RecyclerView(带有列表).显示第二个回收站时,您无法上下滑动BottomSheet,即使在展开"状态下,列表也仍在滚动.如果第一个回收站启动,一切都很好.有没有办法使BottomSheet上下滑动?

I got two RecyclerView inside a LinearLayout with a BottomSheetBehavior. When you click on a item inside the first RecyclerView (with a grid) the RecyclerView is set to Gone and an the second RecyclerView (with a list) is shown. When the second Recycler is shown you cant slide the BottomSheet up and down instead the List is scrolling even in Expanded State. If the First Recycler is up everything is fine. Is there a way to make the BottomSheet to slide up and down again?

<LinearLayout
        android:id="@+id/sliding_layout_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:orientation="vertical"
        app:behavior_hideable="false"
        app:behavior_peekHeight="400dp"
        app:layout_behavior="@string/bottomSheetBehavior">

        <android.support.v7.widget.RecyclerView 
           android:id="@+id/grid"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:layout_marginEnd="@dimen/activity_horizontal_margin"
           android:layout_marginStart="@dimen/activity_horizontal_margin"
           android:background="@color/white"
           android:clickable="true"
           android:scrollbars="none" />

        <android.support.v7.widget.RecyclerView 
           android:id="@+id/list"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:layout_marginEnd="@dimen/activity_horizontal_margin"
           android:layout_marginStart="@dimen/activity_horizontal_margin"
           android:background="@color/white"
           android:clickable="true"
           android:scrollbars="none" />
</LinearLayout>

GridAdapter:

GridAdapter:

   @Override
   public void onBindViewHolder(ViewHolder holder, int position) {

    String categorieName = mCategories.get(position);
    final CategoryFilterEvent event = new   CategoryFilterEvent(categorieName);
    holder.grid_item_label.setText(categorieName);

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            EventBus.getDefault().post(event);
        }
    });
}

MainActivity:

MainActivity:

 @Override
 public void onCreate(Bundle savedInstanceState) {

    linearLayoutManager = new LinearLayoutManager(this);
    listAdapter = new ListAdapter(this, mList);
    recyList.setAdapter(listAdapter);
    recyList.setLayoutManager(linearLayoutManager);

    gridLayoutManager = new GridLayoutManager(this, 3);
    gridAdapter = new GridAdapter(this, new ArrayList<String>());
    recyGrid.setAdapter(gridAdapter);
    recyGrid.setLayoutManager(gridLayoutManager);
}

public void onEventMainThread(CategoryFilterEvent event) {
    recyGrid.setVisibilty(GONE);
    recyList.setVisiblity(VISIBLE);
}

推荐答案

BottomSheetBehavior的实现不支持内部的两个可滚动视图,这就是为什么这种布局永远都不能开箱即用"的原因.但是,有一个hacky,但是此问题的简单解决方法.首先,我们必须通过将该类的代码复制到我们的新CustomBottomSheetBehavior类中来制作自定义BottomSheetBehavior.然后,通过替换该行来修改"onLayoutChild"方法

The implementation of BottomSheetBehavior doesn't support two scrollable views inside, that's why this layout will never work "out of the box". However, there is a hacky, but simple workaround to this problem. First, we have to make custom BottomSheetBehavior by copying that class' code to our new CustomBottomSheetBehavior class. Than, modify "onLayoutChild" method by replacing the line

mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));

if (mNestedScrollingChildRef == null) {
    mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
}

mNestedScrollingChildRef在BottomSheetBehavior类中具有程序包级别的访问权限,因此我们无法对其进行扩展.

mNestedScrollingChildRef has package level access in BottomSheetBehavior class, so there is no way we can extend it.

然后,添加以下方法:

public void setNestedScrollingChildRef(View v) {
    this.mNestedScrollingChildRef = new WeakReference<View>(v);
}

在您的Activity类中:

And in your Activity class:

 RecyclerView recyGrid = (RecyclerView)findViewById(R.id.grid);
 RecyclerView recyList = (RecyclerView)findViewById(R.id.list);
 layout = (LinearLayout)findViewById(R.id.sliding_layout_container);

 recyGrid.addOnItemTouchListener(onItemTouchListener);
 recyList.addOnItemTouchListener(onItemTouchListener);

onItemTouchListener代码:

onItemTouchListener code:

RecyclerView.OnItemTouchListener onItemTouchListener = new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        setScrollable(layout, rv);
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
};

private void setScrollable(View bottomSheet, RecyclerView recyclerView){
    ViewGroup.LayoutParams params = bottomSheet.getLayoutParams();
    if (params instanceof CoordinatorLayout.LayoutParams) {
        CoordinatorLayout.LayoutParams coordinatorLayoutParams = (CoordinatorLayout.LayoutParams) params;
        CoordinatorLayout.Behavior behavior = coordinatorLayoutParams.getBehavior();
        if (behavior != null && behavior instanceof CustomBottomSheetBehavior)
            ((CustomBottomSheetBehavior)behavior).setNestedScrollingChildRef(recyclerView);
    }
}

我们在这里捕获所有触摸事件,这些事件进入recyclerViews,并将其作为mNestedScrollingChildRef添加到CustomBottomSheetBehavior类,以便可以正确处理所有滚动事件.

What we do here is catching all touch events, that come to recyclerViews and add it as a mNestedScrollingChildRef to CustomBottomSheetBehavior class, so that all scrolling events could be handled in a right way.

2018年2月27日更新 将这种方法与BottomSheetDialogFragment一起使用会涉及进一步的复制粘贴.我们应该创建用于扩展AppCompatDialog的CustomBottomSheetDialog,然后在其中复制BottomSheetDialog类中的所有代码.然后将上面我描述过的类变量mBehavior更改为CustomBottomSheetBehavior.

Update of 27.02.2018 Using this approach with BottomSheetDialogFragment involves further copy-pasting. We should create CustomBottomSheetDialog that extends AppCompatDialog and copy there all the code from class BottomSheetDialog. Then change there class variable mBehavior to be of CustomBottomSheetBehavior, that I described above.

然后,修改"wrapInBottomSheet"方法以在那里设置新行为:

Then, modify "wrapInBottomSheet" method to set new behavior there:

ViewGroup.LayoutParams bottomSheetParams = bottomSheet.getLayoutParams();
    if (bottomSheetParams instanceof CoordinatorLayout.LayoutParams) {
        mBehavior = new CustomBottomSheetBehavior<>();
        mBehavior.setBottomSheetCallback(mBottomSheetCallback);
        mBehavior.setHideable(mCancelable);
        mBehavior.setPeekHeight(*some value here*);
        ((CoordinatorLayout.LayoutParams) bottomSheetParams).setBehavior(mBehavior);
    }

然后在您的片段类中重写"onCreateDialog"方法以在其中使用CustomBottomSheetDialog:

And in your fragment class override "onCreateDialog" method to use CustomBottomSheetDialog there:

  @NonNull
  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState) {
    CustomBottomSheetDialog  dialog = new CustomBottomSheetDialog (getActivity(), R.style.YourDialogTheme);
    dialog.setContentView(R.layout.bottom_sheet_page_fragment);

     RecyclerView recyGrid = (RecyclerView)dialog.findViewById(R.id.grid);
     RecyclerView recyList = (RecyclerView)dialog.findViewById(R.id.list);
     layout = (LinearLayout)dialog.findViewById(R.id.sliding_layout_container);

     recyGrid.addOnItemTouchListener(onItemTouchListener);
     recyList.addOnItemTouchListener(onItemTouchListener);
     return dialog;
    }

其余代码保持不变.

这篇关于具有两个RecyclerView的BottomSheetBehavior的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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