ActionBar 下方的 Persistent BottomSheet

Posted

技术标签:

【中文标题】ActionBar 下方的 Persistent BottomSheet【英文标题】:Persistent BottomSheet below ActionBar 【发布时间】:2017-07-18 09:33:56 【问题描述】:

我有一个带有自定义 toolbar 和持久 BottomSheet 的应用布局 - 两者都在 CoordinatorLayout 内。

单击按钮时,我想显示BottomSheet。现在工作表全屏显示并覆盖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_
    android:layout_
    tools:context="com.test.MainActivity">

    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:layout_
        app:elevation="20dp"
        android:elevation="20dp"
        android:layout_>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            app:elevation="20dp"
            android:elevation="20dp"
            android:layout_
            android:layout_
            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_
    android:layout_
    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_
        android:layout_
        android:text="Lorem Ipsum Dolor..."
        android:textColor="#FFFFFF" />
</RelativeLayout>

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

【问题讨论】:

可以上传截图吗? 屏幕截图添加到问题 - 编辑 您尝试将布局设置为从底部到工具栏的高度,并将底部表设为子级,然后将其设置为与父级高度匹配(新布局) 谢谢!伟大而简单的想法。让它工作的另一件事 BottomSheet 必须是 CoordinatorLayout 的孩子! 就像将 coordinatorLayout 设置为新的父高度一样简单,所以它就像:Layout -> coordinator -> bottomsheet 【参考方案1】:

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

尝试将您的 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_
  android:layout_
  tools:context="com.test.MainActivity">

    <LinearLayout
      android:layout_
      android:layout_
      android:orientation="vertical">

        <android.support.design.widget.AppBarLayout
          android:layout_
          app:elevation="20dp"
          android:elevation="20dp"
          android:layout_>

          <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            app:elevation="20dp"
            android:elevation="20dp"
            android:layout_
            android:layout_
            android:background="?attr/colorPrimary"/>
        </android.support.design.widget.AppBarLayout>
    </LinearLayout>

    <android.support.design.widget.CoordinatorLayout
      android:layout_
      android:layout_
      android:layout_marginTop="56dp">
      
      <include layout="@layout/bottom_sheet_additem"/>

    </android.support.design.widget.CoordinatorLayout>

</CoordinatorLayout>

希望对你有帮助。

【讨论】:

它对我有用,即使没有边距,但它背后的原因是什么? 这是一个了不起的 hack xD。 这不是好办法。因为在复杂的视图中,在第二个 Coordinator 布局中与其他一些例如 botton_sheet_behaviour 的组合,它会突然关闭或隐藏! @Mahdi 你找到解决方案了吗? @BackPacker 是的。我找到一个。现在使用 compose 将解决所有这些问题。【参考方案2】:

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

<android.support.design.widget.CoordinatorLayout
  android:layout_
  android:layout_
  app:layout_behavior="@string/appbar_scrolling_view_behavior">

  <include layout="@layout/bottom_sheet_additem"/>

</android.support.design.widget.CoordinatorLayout>

【讨论】:

【参考方案3】:

您的 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_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main">

 <RelativeLayout
    android:id="@+id/bottom_sheet"
    android:layout_
    android:layout_
    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>

【讨论】:

【参考方案4】:

当您将底部工作表展开到全屏时,接受的答案有效,但是在折叠它时,它会添加额外的边距,使折叠布局的一部分隐藏在屏幕下方,所以我决定通过聆听以编程方式放置边距到BottomSheet的折叠/隐藏状态。

首先在 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) 

    
);

【讨论】:

【参考方案5】:

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

在BottomSheetCallback 中使用onStateChanged 方法意味着对BottomSheet 已经展开或折叠的事件进行操作。在此阶段添加或删除边距可能会导致看到“生涩”行为,例如工作表暂时达到覆盖应用栏的完全展开状态,然后以编程方式应用边距以向下移动 UI 组件,从而导致“闪烁”为这适用。

相反,我使用 onSlide 方法来检测 BottomSheet 何时向上或向下滑动,并且仅在工作表通过过渡的一半时添加或删除边距。如果在滑动动作中太早应用边距,那么用户可以再次看到 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");
            
        

【讨论】:

请问oldOffSet是什么? @tuanvn91 oldOffset 只是在新的 BottomSheetBehavior.BottomSheetCallback() 中声明的浮点数,其中包含上面运行的 onSlide 方法。您将在上面看到它设置为 slideOffset 的当前值,这意味着在下一次调用 onSlide 时,当前的 slideOffset 可以与前一个进行比较,因此可以判断幻灯片的方向,无论是展开还是折叠。

以上是关于ActionBar 下方的 Persistent BottomSheet的主要内容,如果未能解决你的问题,请参考以下文章

让 DrawerLayout 在 ActionBar 上滑动

AppCompat 操作栏库不显示添加的片段

使用 DrawerLayout 实现 Material Design风格的侧滑

透明操作栏:自定义标签颜色

ActionBar

自定义ActionBar