ActionBar 下方的持久性 BottomSheet

Persistent BottomSheet below ActionBar

我有一个带有自定义 toolbar 和持久 BottomSheet 的应用程序布局 - 都在 CoordinatorLayout.

点击按钮我想显示 BottomSheet。现在 sheet 全屏显示并覆盖 toolbar。通过将应用主题设置为 Theme.AppCompat.Light.DarkActionBarBottomSheet 保持在 ActionBar 以下,但无法自定义栏。

有没有办法将持久化 BottomSheet 的高度限制为全屏 - ActionBar 高度?

这是我在 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>

这里是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>

左侧的图像显示 BottomSheet 停在 Toolbar 下方 - 这不适用于我当前的代码。目前看起来像右图。

我遇到了同样的问题...我不知道这是否是最好的解决方案,但就目前而言,对我有用。

尝试将您的 include 放入 activity_main.xml 中的另一个 CoordinatorLayout 中,并使用这样的 marginTop:

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

希望对您有所帮助。

我们可以使用app:layout_behavior代替固定高度

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

你的 sheet_bottom 应该是这样的

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

接受的答案在您将底部 sheet 展开到全屏时有效,但在折叠它时,它会增加额外的边距,使折叠布局的一部分隐藏在屏幕下方,所以我决定通过监听 BottomSheet.

的 collapse/hidden 状态以编程方式放置边距

首先在xml

中的CoordintorLayout内添加BottomSheet

并在下面添加回调监听器。

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

    }
});

+1 用于以编程方式更新边距。虽然 BottomSheet 的隐藏部分可以通过增加 peek 高度来抵消,但仅使用上面的原始解决方案意味着边距投影到底层 UI 元素上,因此滚动操作区域从实际 BottomSheet 投影到另一个 UI.

在BottomSheetCallback 中使用onStateChanged 方法意味着对BottomSheet 已经展开或折叠的事件进行操作。在此阶段添加或删除边距可能会导致看到 'jerky' 行为,例如 sheet 在以编程方式应用边距以移动 [=26= 之前暂时达到覆盖应用栏的完全展开状态] 组件下降导致 'flash' 因为这适用。

相反,我使用 onSlide 方法检测 BottomSheet 何时向上或向下滑动,并仅在 sheet 过渡到一半时才添加或删除边距。如果在幻灯片运动中过早应用边距,则用户可以再次看到 BottomSheet UI 在启动操作后不久向上或向下跳动(如果他们有,他们不太可能在中途注意到这一点进行了 'fling' 向上或向下运动。

我还发现获取 AppBar 和状态栏的高度并使用它们来设置所需的填充值以在展开模式下准确放置的效果最好。

可以通过使用小部件以编程方式触发 BottomSheet 状态更改来完全避免这一挑战。

@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");
            }
        }