扩展持久性底部 sheet 时调整回收器视图高度
Adjust recycler view height when persistent bottom sheet is expanded
我有一个固定底部 sheet(基本上是一个按钮)和一个回收器视图,它们都包含在 CoordinatorLayout 中。
展开底部 sheet 时,我不希望它遮挡回收站视图。我可以通过分别在回收站视图的底部 sheet 和 app:layout_dodgeInsetEdges="bottom"
中设置 app:layout_insetEdge="bottom"
来实现这一点。
但是,由于 recycler 视图的高度设置为 android:layout_height="match_parent"
,当底部 sheet 展开时,它的顶部会部分移出屏幕。
相反,我希望回收器视图根据底部的高度动态调整其高度 sheet,这样它就不会再移出屏幕了。我怎样才能做到这一点?
这是完整的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"
app:layout_dodgeInsetEdges="bottom" />
<Button
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/update_all"
android:foreground="?attr/selectableItemBackground"
android:background="@drawable/angled_button"
app:behavior_hideable="false"
app:behavior_peekHeight="0dp"
app:layout_insetEdge="bottom"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior" />
</android.support.design.widget.CoordinatorLayout>
编辑:添加了屏幕截图
没有底部sheet一切看起来都很好。
随着底部 sheet 展开,回收站视图不再完全可见。
编辑 2:添加了 GIF
尝试将此属性放入 RecyclerView:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
你可以做 2 种解决方案
1是设置top-margin为RecyclerView
因为您的 CoordinatorLayout 没有对齐 RecyclerView
低于 Toolbar
。所以设置上边距 actionBarSize
.
android:layout_marginTop="?actionBarSize"
2 如果你想要 RecyclerView
出现 Toolbar
将android:elevation
设置为RecyclerView
,因为Toolbar
有4dp
高程,21以上版本布局按高程分层。所以设置
<android.support.v7.widget.RecyclerView
...
android:elevation="@dimen/design_appbar_elevation"/>
design_appbar_elevation
值为 16dp
.
最近遇到了同样的问题,没有找到比删除 app:layout_dodgeInsetEdges="bottom"
并改用填充更好的方法。这是如何实现的:
科特林:
val rv = findViewById<RecyclerView>(R.id.recycler_view))
val behavior = BottomSheetBehavior.from(findViewById<Button>(R.id.bottom_sheet))
behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
override fun onSlide(bottomSheet: View, offset: Float) {
rv.setPadding(0, 0, 0, (bottomSheet.height * offset).toInt())
}
override fun onStateChanged(bottomSheet: View, newState: Int){}
})
Java:
RecyclerView rv = (RecyclerView) findViewById(R.id.recycler_view);
BottomSheetBehavior behavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet));
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
rv.setPadding(0, 0, 0, (int)(slidingView.getHeight() * offset));
}
});
优点:
- 屏幕上没有重叠,既没有与工具栏也没有与 BottomSheet 按钮;
- 不会破坏 FAB 的上移功能;
- RecyclerView的滚动可以随着BottomSheet的上滑一起完成;
缺点:
- 不纯XML,需要编码;
- 需要进行额外的更改以保持原始填充(但仍然可能并且相对容易做到)
Nikita 接受的答案思路正确,但有两个问题:
建议的填充公式仅在底部 sheet 完全展开时才正确,因为作为参数提供给 onSlide 回调的 slideOffset 与 peek 高度和底部的完整高度 sheet,而不仅仅是其完整高度
填充不适用于 recyclerview 的快速滚动条,它会继续延伸到底部 sheet。另一方面,保证金的行为符合预期。
这是一个考虑了这两个更正的 Kotlin 实现:
val behavior = BottomSheetBehavior.from(constraintLayout)
behavior.setBottomSheetCallback(object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val margin = behavior.peekHeight + (bottomSheet.height - behavior.peekHeight) * slideOffset
recyclerview.updateLayoutParams<FrameLayout.LayoutParams> { bottomMargin = margin.toInt() }
}
override fun onStateChanged(bottomSheet: View, newState: Int) { /* Nothing to do */ }
})
引用的LayoutParams的类型要根据自己layout中RecyclerView的parent改变。
请注意,RecyclerView 的底部边距应设置为底部 sheet 在布局 xml 中的窥视高度,以便在 activity 时获得正确的布局负载,在发生任何滑动之前。
以上示例针对不可隐藏的底部 sheet,这意味着 slideOffset 参数仅从 0 变为 1。
对于可隐藏底部 sheet,当 slideOffset 介于 -1 和 0 之间时,应使用另一个公式:behavior.peekHeight * (1 + slideOffset)
我有一个固定底部 sheet(基本上是一个按钮)和一个回收器视图,它们都包含在 CoordinatorLayout 中。
展开底部 sheet 时,我不希望它遮挡回收站视图。我可以通过分别在回收站视图的底部 sheet 和 app:layout_dodgeInsetEdges="bottom"
中设置 app:layout_insetEdge="bottom"
来实现这一点。
但是,由于 recycler 视图的高度设置为 android:layout_height="match_parent"
,当底部 sheet 展开时,它的顶部会部分移出屏幕。
相反,我希望回收器视图根据底部的高度动态调整其高度 sheet,这样它就不会再移出屏幕了。我怎样才能做到这一点?
这是完整的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"
app:layout_dodgeInsetEdges="bottom" />
<Button
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/update_all"
android:foreground="?attr/selectableItemBackground"
android:background="@drawable/angled_button"
app:behavior_hideable="false"
app:behavior_peekHeight="0dp"
app:layout_insetEdge="bottom"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior" />
</android.support.design.widget.CoordinatorLayout>
编辑:添加了屏幕截图
没有底部sheet一切看起来都很好。
随着底部 sheet 展开,回收站视图不再完全可见。
编辑 2:添加了 GIF
尝试将此属性放入 RecyclerView:
app:layout_behavior="@string/appbar_scrolling_view_behavior"
你可以做 2 种解决方案
1是设置top-margin为RecyclerView
因为您的 CoordinatorLayout 没有对齐 RecyclerView
低于 Toolbar
。所以设置上边距 actionBarSize
.
android:layout_marginTop="?actionBarSize"
2 如果你想要 RecyclerView
出现 Toolbar
将android:elevation
设置为RecyclerView
,因为Toolbar
有4dp
高程,21以上版本布局按高程分层。所以设置
<android.support.v7.widget.RecyclerView
...
android:elevation="@dimen/design_appbar_elevation"/>
design_appbar_elevation
值为 16dp
.
最近遇到了同样的问题,没有找到比删除 app:layout_dodgeInsetEdges="bottom"
并改用填充更好的方法。这是如何实现的:
科特林:
val rv = findViewById<RecyclerView>(R.id.recycler_view))
val behavior = BottomSheetBehavior.from(findViewById<Button>(R.id.bottom_sheet))
behavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback(){
override fun onSlide(bottomSheet: View, offset: Float) {
rv.setPadding(0, 0, 0, (bottomSheet.height * offset).toInt())
}
override fun onStateChanged(bottomSheet: View, newState: Int){}
})
Java:
RecyclerView rv = (RecyclerView) findViewById(R.id.recycler_view);
BottomSheetBehavior behavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet));
behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
rv.setPadding(0, 0, 0, (int)(slidingView.getHeight() * offset));
}
});
优点:
- 屏幕上没有重叠,既没有与工具栏也没有与 BottomSheet 按钮;
- 不会破坏 FAB 的上移功能;
- RecyclerView的滚动可以随着BottomSheet的上滑一起完成;
缺点:
- 不纯XML,需要编码;
- 需要进行额外的更改以保持原始填充(但仍然可能并且相对容易做到)
Nikita 接受的答案思路正确,但有两个问题:
建议的填充公式仅在底部 sheet 完全展开时才正确,因为作为参数提供给 onSlide 回调的 slideOffset 与 peek 高度和底部的完整高度 sheet,而不仅仅是其完整高度
填充不适用于 recyclerview 的快速滚动条,它会继续延伸到底部 sheet。另一方面,保证金的行为符合预期。
这是一个考虑了这两个更正的 Kotlin 实现:
val behavior = BottomSheetBehavior.from(constraintLayout)
behavior.setBottomSheetCallback(object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val margin = behavior.peekHeight + (bottomSheet.height - behavior.peekHeight) * slideOffset
recyclerview.updateLayoutParams<FrameLayout.LayoutParams> { bottomMargin = margin.toInt() }
}
override fun onStateChanged(bottomSheet: View, newState: Int) { /* Nothing to do */ }
})
引用的LayoutParams的类型要根据自己layout中RecyclerView的parent改变。
请注意,RecyclerView 的底部边距应设置为底部 sheet 在布局 xml 中的窥视高度,以便在 activity 时获得正确的布局负载,在发生任何滑动之前。
以上示例针对不可隐藏的底部 sheet,这意味着 slideOffset 参数仅从 0 变为 1。
对于可隐藏底部 sheet,当 slideOffset 介于 -1 和 0 之间时,应使用另一个公式:behavior.peekHeight * (1 + slideOffset)