如何设置底部工作表的半展开状态

19

我有一个带有底部工具栏的布局。

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

底部弹出式布局

 <?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>

对我来说,很有必要让我的底部工作表先打开一半,并且在重新拖动后才能打开到全屏。Google地图应用程序是如何完成这项任务的呢?但是我不知道该如何做到这一点。

6个回答

45

充分发挥框架的潜力更好。正如官方文档所述,对于方法setFitToContents

设置扩展表的高度是由其内容的高度确定还是在两个阶段(父容器高度的一半,父容器的完整高度)中扩展。默认值为true。

所以您需要使用以下代码将setFitToContent设置为false

behavior = BottomSheetBehavior.from(your_bottom_sheet_xml)
behavior.isFitToContents = false
behavior.halfExpandedRatio = 0.6f
用这个三行代码,底部表格将首先扩大到屏幕的60%,然后完全扩大到100%。 希望有所帮助!

halfxpandedRatio? - Arnold Brown
@ArnoldBrown 可在 1.1.0-alpha05 版本中使用。 - Илья Имхолинкс
救了我的一天!!感谢您提供的见解。 - Sandy
1
很棒的解决方案。您也可以使用XML来实现:app:behavior_fitToContents="false"app:behavior_halfExpandedRatio="0.6" - Konstantin Konopko

7

只需将BottomSheetBehaivor状态设置为BottomSheetBehavior.STATE_HALF_EXPANDED即可。 如果需要在完全展开后让用户再次返回到半展开模式,需要将peek高度设置为窗口高度的一半。

val bottomSheetBehavior = BottomSheetBehavior.from<NestedScrollView>(bottom_sheet)
val metrics = resources.displayMetrics
bottomSheetBehavior.peekHeight = metrics.heightPixels / 2
bottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED

6

我已尝试了@Massab@HeyAlex, 但都不能满足我的需求。

以下是使用Kotlin的解决方案,如果您的底部滑动接近展开状态,则保持展开状态;如果接近一半状态,则保持在一半状态;如果接近折叠状态,则保持折叠状态:

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

1
这会破坏fling行为。 - Kochchy
感谢@Kochchy,我同意,我推荐这个解决方案https://dev59.com/UVMI5IYBdhLWcg3wuOCO#59305687 - david

3

虽然这个问题已经得到了解答,但我刚刚找到了另一种实现此行为的方法,所以分享给其他人。

创建一个全局变量,并将其初始化为您的BottomSheetBehavior的默认状态,例如

int state = BottomSheetBehavior.STATE_COLLAPSED;

然后,在BottomSheetBehavior.BottomSheetCallback中,将您的state变量更新为当前状态。

BottomSheetBehavior.STATE_DRAGGING中,如果状态不是一半展开的,则将状态设置为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);
        }
    });

这将使您的BottomSheet分为三个步骤,即折叠半展开展开

希望可以帮助到某些人!


关于 onSlide,我希望将中间位置视为卡片已经滑到顶部。但是我看到的情况是 onSlide 的偏移仍然是屏幕总大小的百分比。 - j2emanue

3
class BottomSheetFragment : BottomSheetDialogFragment() {
    /* inside of your Bottom Sheet Dialog Fragment */
    override fun onStart() {
        super.onStart()
        BottomSheetBehavior.from(requireView().parent as View).apply {
        state = BottomSheetBehavior.STATE_HALF_EXPANDED
       }
    }
}

0
在返回根视图之前,在onCreateView中使用此块。
dialog!!.setOnShowListener { dialog ->
        val d = dialog as BottomSheetDialog
        BottomSheetBehavior.from(requireView().parent as View).apply {
                state = BottomSheetBehavior.STATE_EXPANDED
            }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接