具有两个RecyclerView的BottomSheetBehavior [英] BottomSheetBehavior with two RecyclerView
问题描述
我在带有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屋!