Reputation: 4307
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 the RecyclerView
does not resize as
expected when the BottomSheet
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="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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;
}
};
BottomSheetBehavior
attributes. Could there be device-specific quirks or lifecycle timing
issues causing this jump?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?BottomSheetBehavior
on
certain Android versions/devices?Any insights, debugging tips, or potential workarounds would be greatly appreciated!
Upvotes: 0
Views: 24