I'm experiencing inconsistent behavior with Android's BottomSheetBehavior
on some devices. My app layout contains a CoordinatorLayout
with an AppBarLayout
, a main RecyclerView
, and an included BottomSheet
. The intended behavior is that when the BottomSheet
is expanded, I adjust the bottom padding of the RecyclerView
dynamically (in the BottomSheetBehavior’s onSlide
callback) so that the RecyclerView
resizes and remains fully visible above the bottom sheet.
However, I’ve noticed two problematic issues that occur only on certain devices and in conditions I cannot reliably reproduce on my own test devices:
RecyclerView
Resizing: Sometimes theRecyclerView
does not resize as expected when theBottomSheet
expands. Instead of shrinking its visible area to make room for the bottom sheet, it remains oversized and overlaps with the bottom sheet area.BottomSheet
Jumping: On some devices, the bottom sheet suddenly “jumps” upward and then remains in that state until the user interacts with the screen. This jump seems to happen during the expansion/collapse animation.
This issue occurs more frequently on Android Go devices, though it can also be observed on standard devices. I've recorded a video of the behavior reported by a customer. In the video, in the first few seconds you can see the RecyclerView
resizing issue, and after about 1:30 the BottomSheet
jumping issue becomes apparent.
Below is a simplified version of my layout and behavior code:
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android=";
xmlns:app=";
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Other views like AppBarLayout -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:clipToPadding="false"
android:paddingBottom="80dp" />
<!-- Include the bottom sheet -->
<include layout="@layout/bottom_sheet_pterm" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<!-- NavigationView omitted for brevity -->
</androidx.drawerlayout.widget.DrawerLayout>
BottomSheet
Layout (simplified):
<LinearLayout xmlns:android=";
xmlns:app=";
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="406dp" <!-- Fixed height (56dp + 300dp + 50dp) -->
android:background="#FFFFFF"
android:elevation="5dp"
android:orientation="vertical"
app:behavior_hideable="false"
app:behavior_peekHeight="56dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
... />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewTasti"
android:layout_width="match_parent"
android:layout_height="300dp"
... />
<RadioGroup
android:id="@+id/quantita_radio_group"
android:layout_width="match_parent"
android:layout_height="50dp"
... />
</LinearLayout>
The onSlide
:
private final BottomSheetBehavior.BottomSheetCallback bottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() {
private int lastBottomPadding = -1;
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
scrollProductsToBottom();
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
int bottomPadding = getBottomPadding(bottomSheet, slideOffset);
// Update padding only if it has changed to reduce redundant layout passes.
if (bottomPadding != lastBottomPadding) {
lastBottomPadding = bottomPadding;
int leftPadding = recyclerProdotti.getPaddingLeft();
int topPadding = recyclerProdotti.getPaddingTop();
int rightPadding = recyclerProdotti.getPaddingRight();
recyclerProdotti.setPadding(leftPadding, topPadding, rightPadding, bottomPadding);
}
// Smooth scroll to the last item, throttled
if (slideOffset > 0.9) {
scrollProductsToBottom();
}
}
private int getBottomPadding(View bottomSheet, float slideOffset) {
int extraPadding = (int) (80 * recyclerProdotti.getContext().getResources().getDisplayMetrics().density);
// Calculate the dynamic bottom padding based on the bottom sheet's state.
// Here bottomSheet.getPeekHeight() is the starting padding,
// and we add a proportion of the remaining space as the sheet slides.
int bottomPadding = (int) (bottomSheetTasti.getPeekHeight() +
slideOffset * (bottomSheet.getHeight() - bottomSheetTasti.getPeekHeight()));
// Add the extra 80dp in pixels
bottomPadding += extraPadding;
return bottomPadding;
}
};
- What might be causing the bottom sheet to “jump” upward on some
devices until user interaction? I've ensured the bottom sheet has a
fixed height (406dp) and used the proper
BottomSheetBehavior
attributes. Could there be device-specific quirks or lifecycle timing issues causing this jump? - Why might the
RecyclerView
sometimes not resize as expected? I adjust its bottom padding during the onSlide callback, but the change isn’t consistently applied. Could it be related to the fixed height of the bottom sheet or other layout interactions within the CoordinatorLayout? - Are there known issues or workarounds with
BottomSheetBehavior
on certain Android versions/devices?
Any insights, debugging tips, or potential workarounds would be greatly appreciated!