BottomSheetBehavior中RecyclerView无法完全向下滚动如何解决?
问题分析
当BottomSheet处于半展开(peekHeight对应状态)时,RecyclerView无法滚动到底部的核心原因有两点:
- RecyclerView配置了
app:layout_behavior="@string/appbar_scrolling_view_behavior",这个Behavior是为配合AppBarLayout滚动设计的,在BottomSheet场景中会干扰RecyclerView的布局测量与滚动范围计算。 - BottomSheet半展开时,实际显示高度被限制为
peekHeight,但RecyclerView仍按父布局总高度(450dp)计算自身高度,导致部分列表项被BottomSheet的可视区域裁剪,无法滚动到。
解决方案
步骤1:移除RecyclerView的冗余Behavior
修改activity_test_sheet.xml中的RecyclerView配置,删除冲突的Behavior:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:nestedScrollingEnabled="true" android:overScrollMode="never" android:scrollbars="none"/>
步骤2:监听BottomSheet状态,动态调整RecyclerView高度
在Activity中添加BottomSheet状态监听器,根据当前状态计算RecyclerView的可用高度,确保滚动范围与BottomSheet可视区域匹配:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); recyclerView = findViewById(R.id.recyclerView); bottomSheetLayout = findViewById(R.id.bottomSheetLayout); sheetBehavior = BottomSheetBehavior.from(bottomSheetLayout); RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(); RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setAdapter(recyclerViewAdapter); // 顶部拖动View的高度(对应布局中50dp的View) final int topViewHeight = 50 * getResources().getDisplayMetrics().densityDpi / 160; // BottomSheet的peekHeight与总高度 final int peekHeight = sheetBehavior.getPeekHeight(); final int sheetTotalHeight = 450 * getResources().getDisplayMetrics().densityDpi / 160; // 监听BottomSheet状态变化 sheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { LinearLayout.LayoutParams rvParams = (LinearLayout.LayoutParams) recyclerView.getLayoutParams(); if (newState == BottomSheetBehavior.STATE_COLLAPSED || newState == BottomSheetBehavior.STATE_SETTLING) { // 半展开/ Settling状态:RecyclerView高度=peekHeight - 顶部View高度 rvParams.height = peekHeight - topViewHeight; } else if (newState == BottomSheetBehavior.STATE_EXPANDED) { // 完全展开状态:RecyclerView高度=BottomSheet总高度 - 顶部View高度 rvParams.height = sheetTotalHeight - topViewHeight; } recyclerView.setLayoutParams(rvParams); } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { // 可选:滑动过程中根据偏移量动态调整高度,优化过渡体验 } }); recyclerView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { sheetBehavior.setDraggable(false); } else if (event.getAction() == MotionEvent.ACTION_UP) { sheetBehavior.setDraggable(true); } v.onTouchEvent(event); return true; } }); }
可选优化:用尺寸资源替代硬编码
在res/values/dimens.xml中定义尺寸,让代码更易维护:
<dimen name="bottom_sheet_top_view_height">50dp</dimen> <dimen name="bottom_sheet_total_height">450dp</dimen>
之后在Activity中通过getResources().getDimensionPixelSize(R.dimen.xxx)获取数值即可。
验证效果
修改完成后,当BottomSheet处于半展开(STATE_SETTLING/STATE_COLLAPSED)状态时,RecyclerView的高度会自动适配当前可视区域,列表项可以完全滚动到底部;完全展开时恢复最大高度,保持原有滚动体验。
内容的提问来源于stack exchange,提问作者Kristian
相关产品推荐
相关产品推荐

