在咱们的开发中常常会遇到从底部弹出对话框的需求。在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
的所有。