BottomSheet詳解

關係

  1. BottomSheet不是真正存在的類,而是一種稱呼,表示該種控件類型,參照Google翻譯,本文如下稱之爲「底頁」,就是從屏幕底部彈出的工具條。與之對應是BottomSheetBehavior的行爲類,它須要附屬某個控件使用。該行爲性質包括:
    • 能夠從底部彈出
    • 能夠上下拖拽佈局
    • 能夠單擊淡黑色遮罩隱藏/關閉
  2. BottomSheetDialog繼承Dialog,是一種對話框,它是擁有BottomSheetBehavior行爲的對話框,從而實現從底部彈出和上下拉伸的效果。
  3. BottomSheetDialogFragment是包含BottomSheetDialog的片斷(Fragment),因此它能夠同時利用Fragment的特色和BottomSheet這一交互效果。

BottomSheetBehavior

使用

在xml佈局文件中與CoordinatorLayout配合使用。以下設置後,NestedScrollView具備BottomSheetBehavior的性質,且一開始就顯示在佈局中,初始的顯示高度爲peekHeight值。背景沒有淡黑色遮罩,能夠上下拖拽。php

  • 關鍵語句app:layout_behavior="@string/bottom_sheet_behavior"java

  • NestedScrollView的子視圖只能有一個。android

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true">

    <android.support.v4.widget.NestedScrollView android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" app:behavior_hideable="true" app:behavior_peekHeight="50dp" app:layout_behavior="@string/bottom_sheet_behavior">
        
        <!--內部佈局-->
        
    </android.support.v4.widget.NestedScrollView>
    
</android.support.design.widget.CoordinatorLayout>
複製代碼

上述代碼中有兩個屬性值得注意。app

  • app:behavior_hideable:當咱們上下拖拽時,佈局是否能夠所有隱藏。若是設置爲真,那麼你向下滑完以後,佈局會被隱藏起來,而後就滑不出來了。。。(除非你寫了按鈕之類的邏輯控制它的行爲)因此要謹慎。
  • app:behavior_peekHeight:是當底頁關閉的時候,底部咱們能看到的高度,默認是0不可見。

獲取行爲

在佈局文件中聲明以後,就能夠在代碼中獲取行爲了。ide

// 獲取視圖
View = findViewById(R.id.bottom_sheet);
// 獲取行爲
BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
複製代碼

方法

行爲的一些經常使用的方法。工具

方法名 用法示例 說明
setHideable setHideable(true) 對應app:behavior_hideable屬性
setPeekHeight setPeekHeight(500) 對應app:behavior_peekHeight屬性
setBottomSheetCallback / 設置監聽回調
setState setState(BottomSheetBehavior.STATE_EXPANDED) 設置底頁狀態

BottomSheetCallback

底頁的監聽回調事件。佈局

behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
	@Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        //監聽BottomSheet狀態的改變
    }
	@Override
    public void onSlide(@NonNull View bottomSheet, float slideOffset) {
        //監聽拖拽中的回調,根據slideOffset能夠作一些動畫
    }
});
複製代碼

底頁行爲一共有五種狀態。post

  • STATE_HIDDEN: 隱藏狀態。默認是false,可經過app:behavior_hideable屬性設置。動畫

  • STATE_COLLAPSED: 摺疊關閉狀態。可經過app:behavior_peekHeight來設置顯示的高度,peekHeight默認是0。idea

  • STATE_DRAGGING: 被拖拽狀態

  • STATE_SETTLING: 拖拽鬆開以後到達終點位置(collapsed or expanded)前的狀態。

  • STATE_EXPANDED: 徹底展開的狀態。

BottomSheetDialog

這是具備底頁行爲性質的對話框,不須要與CoordinatorLayout配合使用。彈出時,背景爲出現一層淡黑色遮罩。須要相關邏輯控制它的彈出。

使用——佈局文件

設計BottomSheetDialog內部的視圖。Xml能夠不用被CoordinatorLayout包裹,可是仍是推薦實用推薦的滑動控件NestedScrollView

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">

    <!-- 內部視圖 -->
    
</android.support.v4.widget.NestedScrollView>
複製代碼

使用——代碼文件

使用上述的佈局文件,假設名稱爲layout_bsd。能夠獲取行爲實現自定義。要注意的是從視圖的父視圖((View)view.getParent())獲取底頁行爲,不然會報錯:

The view is not a child of CoordinatorLayout.

BottomSheetDialog dialog = new BottomSheetDialog(context);
View view = getLayoutInflater.inflate(R.layout.layout_bsd, null);
dialog.setContentView(view);
// 獲取行爲,用於自定義
BottomSheetBehavior behavior = BottomSheetBehavior.from((View)view.getParent());
dialog.show();
複製代碼

BottomSheetDialogFragment

有兩種用法。

  • 看成中裝了一個底頁對話框的Fragment。實際是與底頁對話框的做用和使用方法是相同的。
  • 具備底頁行爲的Fragment

用法一——披着Fragment外衣的BottomSheetDialog

重寫BottomSheetDialogFragment中的onCreateDialog方法。能夠看到和上面BottomSheetDialog的代碼是相同的。一樣能夠在中間獲取行爲用於自定義。要注意是子視圖的擴充用到的是View.inflate的靜態方法,不然會報錯。

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    BottomSheetDialog dialog = (BottomSheetDialog) super.onCreateDialog(savedInstanceState);
    View view = View.inflate(getContext(), R.layout.dialog_bottom_sheet, null);
    dialog.setContentView(view);
    mBehavior = BottomSheetBehavior.from((View) view.getParent());
    return dialog;
}
複製代碼

用法二——真正的Fragment

重寫BottomSheetDialogFragment中的onCreateView方法。代碼與Fragment的常規寫法相同。不過很差的一點是不容易獲取行爲。若是要強行獲取行爲的話,可使用如下的代碼。

@Override
public void onStart() {
	super.onStart();
    Dialog dialog = getDialog();
    
    if (dialog != null) {
        View bottomSheet = dialog.findViewById(R.id.design_bottom_sheet);
        bottomSheet.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
    }
    View view = getView();
    view.post(() -> {
        View parent = (View) view.getParent();
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) (parent).getLayoutParams();
        CoordinatorLayout.Behavior behavior = params.getBehavior();
        BottomSheetBehavior bottomSheetBehavior = (BottomSheetBehavior) behavior;
        bottomSheetBehavior.setPeekHeight(view.getMeasuredHeight());
        ((View)bottomSheet.getParent()).setBackgroundColor(Color.TRANSPARENT);
    });
}
複製代碼

可是若是這兩個方法都重寫了,那麼以onCreateView裏的視圖爲準,onCreateDialog會被覆蓋。

擴展:經過設置style實現圓角樣式

以下設置好以後,在建立BottomSheetDialog時傳入樣式。

BottomSheetDialog dialog = new BottomSheetDialog(context, R.style.BottomSheetDialog);
複製代碼
<!--styles.xml文件-->
<style name="BottomSheet" parent="Widget.Design.BottomSheet.Modal"> <!--背景,頂部兩個圓角--> <item name="android:background">@drawable/bg_bottom_sheet</item> </style>
<style name="BottomSheetDialog" parent="Theme.Design.Light.BottomSheetDialog"> <item name="android:windowIsFloating">false</item> <!--底部彈出條的樣式(至關於背景)--> <item name="bottomSheetStyle">@style/BottomSheet</item> <!--狀態欄顏色--> <item name="android:statusBarColor">@color/transparent</item> <!--導航條顏色--> <item name="android:navigationBarColor">@color/white</item> </style>

<!--如下是@drawable/bg_bottom_sheet-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp">
    </corners>
    <solid android:color="@android:color/white"/>
    <padding android:top="16dp" android:left="8dp" android:right="8dp" />
</shape>
複製代碼

效果圖

BottomSheet效果

參考

相關文章
相關標籤/搜索