Android底部对话框神器BottomSheetDialog

Android底部对话框神器BottomSheetDialog前言 在以前想让底部弹出一个对话框,一般的做法是继承Dialog,然后设置布局、设置位置、设置高宽,如果还想增加一个从下到上的动画,还需要新建一个动画文件,但是到后来,我们有了官方提供的BottomS

前言

在以前想让底部弹出一个对话框,一般的做法是继承Dialog,然后设置布局、设置位置、设置高宽,如果还想增加一个从下到上的动画,还需要新建一个动画文件,但是到后来,我们有了官方提供的BottomSheetDialogFragmentBottomSheetDialogbottomSheetBehavior这几个类,几行代码就可以实现上述效果。

如下所示,就可以简单创建一个底部弹出的Dialog。

var bottomSheetDialog = BottomSheetDialog(this)
bottomSheetDialog.setContentView(R.layout.dialog)
bottomSheetDialog.show()

录屏_选择区域_20210925170605.gif

还可以使用BottomSheetDialogFragmentBottomSheetDialogFragment继承自DialogFragment ,在需要的时候我们可以重写onCreateDialog方法,返回自定义的Dialog,他默认也是返回BottomSheetDialog

public class BottomSheetDialogFragment extends AppCompatDialogFragment {
  private boolean waitingForDismissAllowingStateLoss;
  @NonNull
  @Override
  public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    return new BottomSheetDialog(getContext(), getTheme());
  }
  .....
}

拖拽

如果视图中有很多东西要展示,默认可以只展示一部分,另一部分可以向上拖拽显示,这个具体是怎么计算的,可以继续往下看,在这里,只需要新建一个dialog布局,高度设置成match_parent即可。

class MemberBottomSheetDialog : BottomSheetDialogFragment() {
    override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? = inflater.inflate(R.layout.dialog, container, false)
}

MemberBottomSheetDialog().show(supportFragmentManager,"TAG")

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent" android:background="#ffffff" android:layout_height="match_parent">

    <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent">

    </FrameLayout>
</RelativeLayout>

录屏_选择区域_20210925171341.gif

但是你会发现,只有当根布局是RelativeLayout的时候,内容才会显示出来。

修改高度

由于BottomSheetDialogFragment使用的是BottomSheetDialog,他默认的高度计算方式是parentHeight - parentWidth * 9 / 16,但是他对外提供了一个方法给我们,用来设置开始时候的状态,如下所示:

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    var bottomSheetDialog = BottomSheetDialog(context!!);
    bottomSheetDialog.behavior.peekHeight=100;
    return bottomSheetDialog
}

默认展开

还有个问题是,默认是不展开的,如果想展开,也就是全屏,可以设置stateBottomSheetBehavior.STATE_EXPANDED

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    if (dialog is BottomSheetDialog) {
        val behaviour = (dialog as BottomSheetDialog).behavior behaviour.state = BottomSheetBehavior.STATE_EXPANDED }
}

禁止拖拽

官方对setDraggable的解释是:设置是否可以通过拖动折叠/展开,禁用拖动时,应用程序需要实现自定义方式来展开/折叠对话框。

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog

    bottomSheetDialog.behavior.isDraggable=false

    return bottomSheetDialog
}

背景不变暗

默认情况下,弹出对话框时,会便暗,这其实加个样式就可以了。

<style name="myDialog" parent="Theme.MaterialComponents.BottomSheetDialog"> <item name="android:backgroundDimEnabled">false</item> </style>
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return BottomSheetDialog(context!!, R.style.myDialog)
}

监听滚动

有时候还需要在向上拖拽时候做一些联动,就需要获取对话框滑动的值,可以通过behavior.addBottomSheetCallback来实现。

slideOffset的值是0-1之间,默认状态下是0,滑动到顶部的时候值是1,消失的时候值是-1,

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    val bottomSheetDialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
    bottomSheetDialog.behavior.addBottomSheetCallback(object :
        BottomSheetBehavior.BottomSheetCallback() {
        override fun onStateChanged(bottomSheet: View, newState: Int) {
            Log.i(TAG, "onStateChanged: ")
        }
        override fun onSlide(bottomSheet: View, slideOffset: Float) {
            Log.i(TAG, "onSlide: ${slideOffset}")
        }
    })
    return bottomSheetDialog
}

向上拖拽时候是怎么计算的?

这个问题很简单,他内部拖拽是通过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。

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">

    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical">

        <Button android:id="@+id/bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="打开" />
    </LinearLayout>

    <LinearLayout android:background="@color/cardview_dark_background" android:id="@+id/design_bottom_sheet1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:behavior_hideable="true" app:behavior_peekHeight="300dp" app:elevation="6dp" app:layout_behavior="@string/bottom_sheet_behavior"></LinearLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
  var bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.design_bottom_sheet1));
 bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
 findViewById<View>(R.id.bt).setOnClickListener {
     if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_HIDDEN) {
         bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED)
     } else if (bottomSheetBehavior.state == BottomSheetBehavior.STATE_COLLAPSED) {
         bottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
     }
 }

今天的文章Android底部对话框神器BottomSheetDialog分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/14256.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注