前言
在以前想让底部弹出一个对话框,一般的做法是继承Dialog,然后设置布局、设置位置、设置高宽,如果还想增加一个从下到上的动画,还需要新建一个动画文件,但是到后来,我们有了官方提供的BottomSheetDialogFragment
、BottomSheetDialog
、bottomSheetBehavior
这几个类,几行代码就可以实现上述效果。
如下所示,就可以简单创建一个底部弹出的Dialog。
1 | java复制代码var bottomSheetDialog = BottomSheetDialog(this) |
还可以使用BottomSheetDialogFragment
,BottomSheetDialogFragment
继承自DialogFragment
,在需要的时候我们可以重写onCreateDialog
方法,返回自定义的Dialog,他默认也是返回BottomSheetDialog
,
1 | java复制代码public class BottomSheetDialogFragment extends AppCompatDialogFragment { |
拖拽
如果视图中有很多东西要展示,默认可以只展示一部分,另一部分可以向上拖拽显示,这个具体是怎么计算的,可以继续往下看,在这里,只需要新建一个dialog布局,高度设置成match_parent
即可。
1 | java复制代码class MemberBottomSheetDialog : BottomSheetDialogFragment() { |
1 | xml复制代码 |
但是你会发现,只有当根布局是RelativeLayout
的时候,内容才会显示出来。
修改高度
由于BottomSheetDialogFragment
使用的是BottomSheetDialog
,他默认的高度计算方式是parentHeight - parentWidth * 9 / 16
,但是他对外提供了一个方法给我们,用来设置开始时候的状态,如下所示:
1 | java复制代码override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
默认展开
还有个问题是,默认是不展开的,如果想展开,也就是全屏,可以设置state
为BottomSheetBehavior.STATE_EXPANDED
。
1 | java复制代码override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
禁止拖拽
官方对setDraggable
的解释是:设置是否可以通过拖动折叠/展开,禁用拖动时,应用程序需要实现自定义方式来展开/折叠对话框。
1 | java复制代码override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
背景不变暗
默认情况下,弹出对话框时,会便暗,这其实加个样式就可以了。
1 | xml复制代码<style name="myDialog" parent="Theme.MaterialComponents.BottomSheetDialog"> |
1 | java复制代码override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
监听滚动
有时候还需要在向上拖拽时候做一些联动,就需要获取对话框滑动的值,可以通过behavior.addBottomSheetCallback
来实现。
slideOffset的值是0-1之间,默认状态下是0,滑动到顶部的时候值是1,消失的时候值是-1,
1 | java复制代码override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
向上拖拽时候是怎么计算的?
这个问题很简单,他内部拖拽是通过ViewDragHelper
方式来完成的,所以当我们不能向上拖拽的时候,通过ViewDragHelper
有两种办法,一是在tryCaptureView
中返回false,二是在clampViewPositionVertical
中返回某个值,这个值返回一个最大的拖拽值,当我们拖拽到最顶部时候,就无法继续向上了。
上面我们说过,默认的高度是parentHeight - parentWidth * 9 / 16
,但如果我们的View小于这个值,那么最终的高度是取最小的,也就是取这个View的值,这样的话,对话框中的内容已经就全部显示出来了,还要上移干什么?
但是如果我们的View高度大于这个值,他就会取parentHeight - parentWidth * 9 / 16
这个值作为Dialog的高度,那么还可以上移多少空间?答案就是View的高度-parentHeight - parentWidth * 9 / 16
。
比如在我的手机上,parentHeight是2159,那么如果View取1600,那么就还可以上移40px,具体实现方式是定义了fitToContentsOffset
变量,这个值就是parentHeight - childHeight,也就是屏幕中空闲的空间,当向上拖拽的时候会触发clampViewPositionVertical
方法,他返回的值作为新的垂直位置,所以当拖拽到顶部时候,会返回fitToContentsOffset
。
BottomSheetBehavior实现底部Dialog
BottomSheetDialog
中也是使用了BottomSheetBehavior来实现的,首先定义一个布局,注意根布局只能是CoordinatorLayout。
1 | xml复制代码<?xml version="1.0" encoding="utf-8"?> |
1 | java复制代码 var bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.design_bottom_sheet1)); |
本文转载自: 掘金