How i can set Half Expanded state for my BottomShe

2020-08-20 04:01发布

问题:

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.

回答1:

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!



回答2:

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


回答3:

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
                }
            }
        }
    })


回答4:

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!