I'm following the material3 spec, using the android material components lib, and implementing light and dark themes.
I have a ConstraintLayout acting as a BottomSheet, and its background color should be affected by the elevation overlay tint. BottomSheets are on the list of material components implementing elevation overlay, but mine is keeping its default color, colorSurface, instead of becoming lighter in dark mode :
(The color doesn't change when the BottomSheet is expanded.)
The only thing that defines my ConstraintLayout as a BottomSheet is the layout_behaviour
attribute, and I'm wondering how this could actually impact background color. Are BottomSheets only present on the previous list for their modal variant ?
If so, how would one implement the elevation overlay on a whole ConstraintLayout ? Through an ElevationOverlayProvider
, as suggested by the second page linked above ?
Here is the simplified layout of my main 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>
Here is the included BottomSheet layout (again, simplified) :
<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>
I've tried a few things on the the ConstraintLayout to trigger the elevation overlay, notably :
style="?attr/bottomSheetStyle"
Initially, the ConstaintLayout had no background set, whereas the title_background
view had one, a drawable used to display "Google Maps-style" rounded corners at the top of the BottomSheet.
My themes come from the Material Theme Builder, so they extend Theme.Material3.Light.NoActionBar
and Theme.Material3.Dark.NoActionBar
. As visible above, I'm using system attributes everywhere I can to keep the standard behaviour.
Assuming the material-components-android library's BottomSheetBehaviour isn't meant to handle the elevation overlay, here's how to apply it to a Layout.
Extend the corresponding layout as follows :
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)
}
}
Simply switch the original layout by this class in your xml layout definition, and voila, the elevation overlay is applied !
Sources : the dark theme documentation page referenced in the question, and this post.
Bonus : for rounded corners at the top of the BottomSheet, change the init method as follows, and define the corner radius (e.g. 8dp) in your dimensions.
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
}