Reputation: 1213
I have an app layout with a custom toolbar
and a persistent BottomSheet
- both inside of a CoordinatorLayout
.
On a button click I want to show the BottomSheet
. Right now the sheet is displayed fullscreen and overlays the toolbar
. By setting the app theme to Theme.AppCompat.Light.DarkActionBar
the BottomSheet
stays below the ActionBar
, but the bar cannot be customized.
Is there a way to limit the height of the persitent BottomSheet
to fullscreen - ActionBar
height?
This is my code in activity_main.xml
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:attrs="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.test.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:elevation="20dp"
android:elevation="20dp"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:elevation="20dp"
android:elevation="20dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
</LinearLayout>
<include layout="@layout/bottom_sheet_additem"/>
</CoordinatorLayout>
Here is the code of sheet_bottom.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottomSheetLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
android:fitsSystemWindows="true"
app:layout_behavior="@string/bottom_sheet_behavior">
<TextView
android:id="@+id/bottomsheet_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Lorem Ipsum Dolor..."
android:textColor="#FFFFFF" />
</RelativeLayout>
The image on the left hand side shows the
BottomSheet
which stops below the Toolbar
- which is not working with my current code. Currently it looks like the picture on the right.
Upvotes: 11
Views: 9191
Reputation: 1
+1 for updating the margin programmatically. While the hidden part of the BottomSheet can be offset by increasing the peek height, using just the original solution above means the margin projects onto the underlying UI elements so the scroll action area projects off the actual BottomSheet onto the other UI.
Using the onStateChanged method in the BottomSheetCallback means acting on the event that the BottomSheet has already expanded or collapsed. Adding or removing the margin at this stage can result in seeing 'jerky' behaviour where for example the sheet momentarily reaches the fully expanded state covering the appbar before the margin is then programmatically applied to shift the UI components down resulting in a 'flash' as this applies.
Instead I used the onSlide method to detect when the BottomSheet was being slid up or down and added or removed the margins only once the sheet was half way through the transition. If the margins are applied too early in the slide motion then again the user can see the BottomSheet UI jumping up or down not long after initiating the action (they are less likely to notice this at the half way point if they have done a 'fling' up or down motion.
Also I found it worked best to fetch the height of the AppBar and the status bar and use those to set the required padding value for accurate placement in expanded mode.
This challenge can be avoided altogether by using a widget to trigger the BottomSheet state change programmatically.
@Override
public void onSlide(View bottomSheet, float slideOffset) {
boolean inRangeExpanding = oldOffSet < slideOffset;
boolean inRangeCollapsing = oldOffSet > slideOffset;
oldOffSet = slideOffset;
if (inRangeCollapsing && slideOffset < 0.5f) {
//reset padding on top of bottomsheet so there is no padding/overlap onto underlying sheet (which overlaps underlying sheet and so interfers with scrolling behaviour
bSheetView.setPadding(0,10,0,0);
Log.d(TAG,"onSlide STATE_COLLAPSING");
} else if(inRangeExpanding && slideOffset > 0.5f){
//reset padding on top of bottomsheet so there is padding/overlap onto underlying sheet so it does not write over the top of the menu appbar
bSheetView.setPadding(0, topMargin,0,0);
Log.d(TAG,"onSlide STATE_EXPANDING");
}
}
Upvotes: 0
Reputation: 40878
The accepted answer works when you expand the bottom sheet to the full screen, but when collapsing it, it adds additional margin that makes a part of the collapsing layout hidden below the screen, so I decided to put the margin programmatically by listening to the collapse/hidden status of the BottomSheet
.
First add the BottomSheet
within a CoordintorLayout
in xml
And add below callback listener.
mBottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
CoordinatorLayout bottomSheet = findViewById(..); // inflate the bottom sheet
CoordinatorLayout.LayoutParams layoutParams =
(CoordinatorLayout.LayoutParams) bottomSheet.getLayoutParams();
if (newState == BottomSheetBehavior.STATE_COLLAPSED)
layoutParams.setMargins(0, 0, 0, 0); // remove top margin
else if (newState == BottomSheetBehavior.STATE_EXPANDED) {
layoutParams.setMargins(0, 100, 0, 0); // add top margin
bottomSheet.setLayoutParams(layoutParams);
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
}
});
Upvotes: 2
Reputation: 1166
I had the same problem... I don't know if it's the best solution, but for now, worked for me.
Try to put your include inside another CoordinatorLayout in your activity_main.xml
, with a marginTop like this:
<android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:attrs="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.test.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:elevation="20dp"
android:elevation="20dp"
android:layout_height="?attr/actionBarSize">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
app:elevation="20dp"
android:elevation="20dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"/>
</android.support.design.widget.AppBarLayout>
</LinearLayout>
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="56dp">
<include layout="@layout/bottom_sheet_additem"/>
</android.support.design.widget.CoordinatorLayout>
</CoordinatorLayout>
I hope it helps.
Upvotes: 27
Reputation: 21
Your sheet_bottom should look like this
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">
<RelativeLayout
android:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:behavior_hideable="true"
app:behavior_peekHeight="?android:attr/actionBarSize"
app:elevation="@dimen/size_5dp"
app:layout_behavior="@string/bottom_sheet_behavior">
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Upvotes: 2
Reputation: 231
We can use app:layout_behavior instead of fixed height
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<include layout="@layout/bottom_sheet_additem"/>
</android.support.design.widget.CoordinatorLayout>
Upvotes: 3