在咱們的開發中常常會遇到從底部彈出對話框的需求。在design
包中,官方爲咱們提供了一種實現,就是BottomSheetDialog
。它的使用和dialog
同樣,看下它的繼承關係就知道了。
html
design
包使用的版本爲27.0.2
下面咱們看下簡單的使用代碼。java
BottomSheetDialog dialog = new BottomSheetDialog(this); dialog.setContentView(R.layout.bottom_dialog_view); dialog.show();
是的。你沒有看錯,這些代碼就夠了。android
BottomSheetDialog
的兄弟還有個BottomSheetDialgFragment
,來看下BottomSheetDialogFragment
的代碼。app
public class BottomSheetDialogFragment extends AppCompatDialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new BottomSheetDialog(getContext(), getTheme()); } }
是的。你仍是沒有看錯,這就是所有的BottomSheetDialogFragment
的代碼。內部就是個BottomSheetDialog
,就不作過多說明了。ide
咱們打開`BottomSheetDialog
的代碼查看的話會發現,實現也很簡單。只有二百行代碼。來看一下。
咱們在使用的時候會調用。setContentView()
方法,這裏有三個重載的方法:函數
@Override public void setContentView(@LayoutRes int layoutResId) { super.setContentView(wrapInBottomSheet(layoutResId, null, null)); } @Override public void setContentView(View view) { super.setContentView(wrapInBottomSheet(0, view, null)); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { super.setContentView(wrapInBottomSheet(0, view, params)); }
咱們能夠看到最後都調用了wrapInBottomSheet()
方法。this
private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) { // #1 final FrameLayout container = (FrameLayout) View.inflate(getContext(), R.layout.design_bottom_sheet_dialog, null); final CoordinatorLayout coordinator = (CoordinatorLayout) container.findViewById(R.id.coordinator); //#2 if (layoutResId != 0 && view == null) { view = getLayoutInflater().inflate(layoutResId, coordinator, false); } //#3 FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet); mBehavior = BottomSheetBehavior.from(bottomSheet); mBehavior.setBottomSheetCallback(mBottomSheetCallback); mBehavior.setHideable(mCancelable); if (params == null) { bottomSheet.addView(view); } else { bottomSheet.addView(view, params); } //...省略部分代碼 return container; }
咱們能夠分兩部分開,#2
部分就是獲取到設置的View
這沒什麼好說的。 #1
獲取了個design_bottom_sheet_dialog
的FrameLayout
。代碼以下:idea
<FrameLayout 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/container" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <View android:id="@+id/touch_outside" android:layout_width="match_parent" android:layout_height="match_parent" android:importantForAccessibility="no" android:soundEffectsEnabled="false" tools:ignore="UnusedAttribute"/> <FrameLayout android:id="@+id/design_bottom_sheet" style="?attr/bottomSheetStyle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|top" app:layout_behavior="@string/bottom_sheet_behavior"/> </android.support.design.widget.CoordinatorLayout> </FrameLayout
這裏就是一個FrameLayout
嵌套了個CoordinatorLayout
,再嵌套了一個View
用於點擊收起Dialog
和底部的FrameLayout
用來顯示咱們爲BottomSheetDialog
設置的視圖。上面wrapInBottomSheet()
也就大體完了。spa
那麼究竟是怎麼作到從底部彈出的呢?這邊就那幾行沒說的了嘛。還用想,確定是他們「搞的鬼」。code
mBehavior = BottomSheetBehavior.from(bottomSheet);
經過這一行咱們建立了一個BottomSheetBehavior
。而正式這個BottomSheetBehavior
讓對話框從底部彈出的。
@Override protected void onStart() { super.onStart(); if (mBehavior != null) { mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED); } }
當Dialog
展現的時候,就調用了。BottomSheetBehavior
的setState(BottomSheetBehavior.STATE_COLLAPSED)
,那爲何調用這個方法就能顯示出來了呢?咱們來看下BottomSheetBehavior
的簡單介紹,以後咱們就明白了。
/** * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as * a bottom sheet. */ public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {...}
這是官方的解釋。主要是用來和CoordinatorLayout
配合來實現底部展現效果的。
主要使用的函數是setState()
方法,狀態有以下幾個:
STATE_DRAGGING
: 被拖動的狀態。STATE_SETTLING
: 拖拽鬆開以後到達終點位置(collapsed or expanded)前的狀態STATE_EXPANDED
: 展開的狀態STATE_COLLAPSED
: 摺疊的狀態STATE_HIDDEN
: 隱藏的狀態。在這裏主要說一下STATE_COLLAPSED
和STATE_EXPANDED
的區別。 再說區別以前咱們須要先看一個參數,mPeekHeight
這個參數就是用來設置STATE_COLLAPSED
狀態下,界面顯示的高度的。當不設置的時候會顯示 view的所有。STATE_EXPANDED
狀態下則會顯示出View的所有。還有一點須要注意的是設置STATE_HIDDEN
的時候須要將mHideable
設置爲true。設置mPeekHeight
和mHideable
的方法都有兩種,分別爲:
set方法
: setPeekHight(height) 和setHideable(hideable)xml
中定義參數:app:behavior_hideable="true" app:behavior_peekHeight="50dp"
經過設置不一樣的狀態來展示出不一樣的效果。參考BottomSheetDialog
的實現咱們就能夠實現一個本身的底部彈出效果了。獲取Behavior
咱們可使用:
mBehavior = BottomSheetBehavior.from(view);
在BottomSheetDialog
中咱們在onStart()
方法中調用了。 mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
,這個時候,咱們爲dialog設置的界面就顯示出來了。那麼爲何沒有摺疊的效果呢?由於BottomSheetDialog
中並無設置mPeekHeight
的值。前面說了。當沒有設置peekHeight
時,STATE_COLLAPSED
狀態下會顯示View
的所有。