I have layout with bottom sheet.
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@color/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main_weather_map" />
<include layout="@layout/bottom_sheet" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Bottom sheet layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 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:id="@+id/bottom_sheet"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:clipToPadding="true"
app:behavior_peekHeight="80dp"
app:layout_behavior="@string/bottom_sheet_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/weather_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
tools:listitem="@layout/item_weather" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
It is necessary for me that my bottom sheet opens first half, and after re-dragging it opens to full screen. How is it done in google maps app. But I have no idea how to do this.
It is better to use the framework with its full potential. As official documentation states for method setFitToContents :
Sets whether the height of the expanded sheet is determined by the height of its contents, or if it is expanded in two stages (half the height of the parent
container, full height of parent container). Default value is true.
So all you need is set setFitToContent
to false
with:
behavior = BottomSheetBehavior.from(your_bottom_sheet_xml)
behavior.isFitToContents = false
behavior.halfExpandedRatio = 0.6f
With this 3-line-code the bottom sheet will expand till 60% of the screen at first, and afterwards it will fully expand to 100%.
Hope it helps!
Just set BottomSheetBehaivor state to BottomSheetBehavior.STATE_HALF_EXPANDED.
Also if you need after full expanding let user again go back to half expanded mode, you need to set peek height to half of window height.
val bottomSheetBehavior = BottomSheetBehavior.from<NestedScrollView>(bottom_sheet)
val metrics = resources.displayMetrics
bottomSheetBehavior.peekHeight = metrics.heightPixels / 2
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
I have tried the @Massab and @HeyAlex but didn't match my desired behavior.
With the following solution in kotlin, if your bottomsheet sliding is near the expanded state, it stays expanded, if is near the half state, stays at half and if it's near collapsed, it stays collapsed:
val bottomSheet = view.findViewById<View>(R.id.bottom_sheet1)
val mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
mBottomSheetBehavior.addBottomSheetCallback(object: BottomSheetBehavior.BottomSheetCallback(){
override fun onStateChanged(bottomSheet: View, newState: Int) {
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val upperState = 0.66
val lowerState = 0.33
if (bottomSheetEventsFilterBehavior.state == BottomSheetBehavior.STATE_SETTLING ) {
if(slideOffset >= upperState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}
if(slideOffset > lowerState && slideOffset < upperState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}
if(slideOffset <= lowerState){
mBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
}
})
Although this question has been answered, but just got another way to implement this behavior so sharing for others.
Create a global variable and initialize it with the default state of your BottomSheetBehavior, like
int state = BottomSheetBehavior.STATE_COLLAPSED;
Then, in BottomSheetBehavior.BottomSheetCallback update your state variable to the current state
and in
BottomSheetBehavior.STATE_DRAGGING, if state is not half expanded,
set the state to BottomSheetBehavior.STATE_HALF_EXPANDED
sheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View view, int i) {
switch (i) {
case BottomSheetBehavior.STATE_COLLAPSED:
state = BottomSheetBehavior.STATE_COLLAPSED;
binder.imgRefresh.setVisibility(View.GONE);
break;
case BottomSheetBehavior.STATE_EXPANDED:
binder.imgRefresh.setVisibility(View.VISIBLE);
state = BottomSheetBehavior.STATE_EXPANDED;
break;
case BottomSheetBehavior.STATE_DRAGGING:
if (state != BottomSheetBehavior.STATE_HALF_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_HALF_EXPANDED);
}
break;
case BottomSheetBehavior.STATE_HALF_EXPANDED:
state = BottomSheetBehavior.STATE_HALF_EXPANDED;
break;
}
}
@Override
public void onSlide(@NonNull View view, float v) {
binder.viewExtender.setAlpha(1 - v);
}
});
This will make your BottomSheet to take three steps , i.e., Collapsed, Half Expanded, Expanded.
Hope it can help someone!