标准 BottomSheet 的海拔覆盖
Elevation overlay for a standard BottomSheet
我遵循 material3 规范,使用 android material components 库,并实现明暗主题。
我有一个作为 BottomSheet 的 ConstraintLayout,它的背景颜色应该受到 elevation overlay tint. BottomSheets are on the list of material 实现高程覆盖的组件的影响,但我的保留其默认颜色 colorSurface,而不是在深色模式下变亮:
(展开 BottomSheet 时颜色不变。)
唯一将我的 ConstraintLayout 定义为 BottomSheet 的是 layout_behaviour
属性,我想知道这实际上会如何影响背景颜色。 BottomSheets 是否只出现在之前的列表中,因为它们的 modal 变体?
如果是这样,如何在整个 ConstraintLayout 上实现高度覆盖?通过上面链接的第二页所建议的 ElevationOverlayProvider
?
这是我主要的简化布局 Activity :
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
...>
<com.google.android.material.appbar.MaterialToolbar
.../>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
... />
<include
android:id="@+id/band_list_bottomsheet"
layout="@layout/bottomsheet_filter_and_sort"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
这是包含的 BottomSheet 布局(再次简化):
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
app:behavior_peekHeight="?android:attr/listPreferredItemHeight"
android:fitsSystemWindows="true"
android:clickable="true"
android:focusable="true"
android:elevation="8dp"
android:background="?attr/colorSurface">
<View
android:id="@+id/title_background"
android:layout_width="0dp"
android:layout_height="?android:attr/listPreferredItemHeight"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/pill"
android:layout_width="25dp"
android:layout_height="5dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/bottomsheet_dragable_pill"
tools:ignore="ContentDescription"/>
<TextView
android:id="@+id/title"
style="@style/TextStyle.BottomSheetTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/filterandsort_sheet_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pill" />
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_title_filter"
style="@style/HorizontalDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_background"/>
<TextView
android:id="@+id/filter_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/filter_title"
style="@style/TextStyle.BottomSheetSubheader"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider_title_filter"/>
...
</androidx.constraintlayout.widget.ConstraintLayout>
我已经在 ConstraintLayout 上尝试了一些方法来触发海拔覆盖,特别是:
- 提高海拔
- 强制其样式为标准 BottomSheet 样式
style="?attr/bottomSheetStyle"
最初,ConstaintLayout 没有设置背景,而 title_background
视图有一个,用于在 BottomSheet 顶部显示“Google 地图样式”圆角的可绘制对象。
我的主题来自 Material Theme Builder,因此它们扩展了 Theme.Material3.Light.NoActionBar
和 Theme.Material3.Dark.NoActionBar
。如上所示,我尽可能地使用系统属性来保持标准行为。
假设 material-components-android 库的 BottomSheetBehaviour 不用于处理海拔叠加层,下面是将其应用于布局的方法。
扩展对应布局如下:
class ElevationOverlayConstraintLayout(context: Context, attributes: AttributeSet) : ConstraintLayout(context, attributes) {
init {
background = MaterialShapeDrawable.createWithElevationOverlay(context, elevation)
}
override fun setElevation(elevation: Float) {
super.setElevation(elevation)
MaterialShapeUtils.setElevation(this, elevation)
}
}
只需在您的 xml 布局定义中通过此 class 切换原始布局,然后 voila,应用海拔叠加!
来源:深色主题 documentation page referenced in the question, and this post。
奖励:对于 BottomSheet 顶部的圆角,按如下方式更改 init 方法,并在尺寸中定义圆角半径(例如 8dp)。
init {
val model = ShapeAppearanceModel()
.toBuilder()
.setTopLeftCorner(CornerFamily.ROUNDED, resources.getDimension(R.dimen.bottomsheet_corner_radius))
.setTopRightCorner(CornerFamily.ROUNDED, resources.getDimension(R.dimen.bottomsheet_corner_radius))
.build()
val shape = MaterialShapeDrawable.createWithElevationOverlay(context, elevation)
shape.shapeAppearanceModel = model
background = shape
}
我遵循 material3 规范,使用 android material components 库,并实现明暗主题。
我有一个作为 BottomSheet 的 ConstraintLayout,它的背景颜色应该受到 elevation overlay tint. BottomSheets are on the list of material 实现高程覆盖的组件的影响,但我的保留其默认颜色 colorSurface,而不是在深色模式下变亮:
唯一将我的 ConstraintLayout 定义为 BottomSheet 的是 layout_behaviour
属性,我想知道这实际上会如何影响背景颜色。 BottomSheets 是否只出现在之前的列表中,因为它们的 modal 变体?
如果是这样,如何在整个 ConstraintLayout 上实现高度覆盖?通过上面链接的第二页所建议的 ElevationOverlayProvider
?
这是我主要的简化布局 Activity :
<androidx.coordinatorlayout.widget.CoordinatorLayout
...>
<com.google.android.material.appbar.AppBarLayout
...>
<com.google.android.material.appbar.MaterialToolbar
.../>
</com.google.android.material.appbar.AppBarLayout>
<fragment
android:id="@+id/navigation_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
... />
<include
android:id="@+id/band_list_bottomsheet"
layout="@layout/bottomsheet_filter_and_sort"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
这是包含的 BottomSheet 布局(再次简化):
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"
app:behavior_peekHeight="?android:attr/listPreferredItemHeight"
android:fitsSystemWindows="true"
android:clickable="true"
android:focusable="true"
android:elevation="8dp"
android:background="?attr/colorSurface">
<View
android:id="@+id/title_background"
android:layout_width="0dp"
android:layout_height="?android:attr/listPreferredItemHeight"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/pill"
android:layout_width="25dp"
android:layout_height="5dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/bottomsheet_dragable_pill"
tools:ignore="ContentDescription"/>
<TextView
android:id="@+id/title"
style="@style/TextStyle.BottomSheetTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/filterandsort_sheet_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/pill" />
<com.google.android.material.divider.MaterialDivider
android:id="@+id/divider_title_filter"
style="@style/HorizontalDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_background"/>
<TextView
android:id="@+id/filter_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/filter_title"
style="@style/TextStyle.BottomSheetSubheader"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider_title_filter"/>
...
</androidx.constraintlayout.widget.ConstraintLayout>
我已经在 ConstraintLayout 上尝试了一些方法来触发海拔覆盖,特别是:
- 提高海拔
- 强制其样式为标准 BottomSheet 样式
style="?attr/bottomSheetStyle"
最初,ConstaintLayout 没有设置背景,而 title_background
视图有一个,用于在 BottomSheet 顶部显示“Google 地图样式”圆角的可绘制对象。
我的主题来自 Material Theme Builder,因此它们扩展了 Theme.Material3.Light.NoActionBar
和 Theme.Material3.Dark.NoActionBar
。如上所示,我尽可能地使用系统属性来保持标准行为。
假设 material-components-android 库的 BottomSheetBehaviour 不用于处理海拔叠加层,下面是将其应用于布局的方法。
扩展对应布局如下:
class ElevationOverlayConstraintLayout(context: Context, attributes: AttributeSet) : ConstraintLayout(context, attributes) {
init {
background = MaterialShapeDrawable.createWithElevationOverlay(context, elevation)
}
override fun setElevation(elevation: Float) {
super.setElevation(elevation)
MaterialShapeUtils.setElevation(this, elevation)
}
}
只需在您的 xml 布局定义中通过此 class 切换原始布局,然后 voila,应用海拔叠加!
来源:深色主题 documentation page referenced in the question, and this post。
奖励:对于 BottomSheet 顶部的圆角,按如下方式更改 init 方法,并在尺寸中定义圆角半径(例如 8dp)。
init {
val model = ShapeAppearanceModel()
.toBuilder()
.setTopLeftCorner(CornerFamily.ROUNDED, resources.getDimension(R.dimen.bottomsheet_corner_radius))
.setTopRightCorner(CornerFamily.ROUNDED, resources.getDimension(R.dimen.bottomsheet_corner_radius))
.build()
val shape = MaterialShapeDrawable.createWithElevationOverlay(context, elevation)
shape.shapeAppearanceModel = model
background = shape
}