BottomSheet
不是真正存在的類,而是一種稱呼,表示該種控件類型,參照Google翻譯,本文如下稱之爲「底頁」,就是從屏幕底部彈出的工具條。與之對應是BottomSheetBehavior
的行爲類,它須要附屬某個控件使用。該行爲性質包括:
BottomSheetDialog
繼承Dialog
,是一種對話框,它是擁有BottomSheetBehavior
行爲的對話框,從而實現從底部彈出和上下拉伸的效果。BottomSheetDialogFragment
是包含BottomSheetDialog
的片斷(Fragment
),因此它能夠同時利用Fragment
的特色和BottomSheet
這一交互效果。在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) | 設置底頁狀態 |
底頁的監聽回調事件。佈局
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: 徹底展開的狀態。
這是具備底頁行爲性質的對話框,不須要與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();
複製代碼
有兩種用法。
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
會被覆蓋。
以下設置好以後,在建立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>
複製代碼