Android DialogFragment快速使用方法

第二篇 解决DialogFragment状态栏亮色问题 - (jianshu.com)

前言

很多人抱怨原生的Dialog不好用,自定义方式比较复杂,这里介绍一下如何使用官方推荐的DialogFragment

使用方法

首先要意识到DialogFragment的本质就是一个Fragment,实现DialogInterface,能够为开发者提供更多便捷的操作。

  • 初始化
    Fragment相同,重写onCreateView加载布局
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.custom_layout, container, false)
}

其中,R.layou.custom_layout是自己定义的布局文件

  • 显示与隐藏
    Dialog一样,使用show()方法显示,但是在DialogFragment中,show()方法需要传入一个FragmentManager保证DialogFragment能够被正确的添加到Activity中。在使用show()方法时,建议重写该方法并判断isAdded
dialogFragment.show(supportFragmentManager) // In Activity
dialogFragment.show(parentFragmentManager) // In Fragment

隐藏DialogFragment,如果使用dismiss()方法会导致某些不可预期的错误,很多网友也分析过,建议使用dismissAllowingStateLoss()替代

默认背景

系统自带的Dialog是有背景的,通常自定义的时候会严重影响美观,需要加上这两句话用来去掉默认的背景:

 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    dialog?.requestWindowFeature(Window.FEATURE_NO_TITLE)
    dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}

如果想调整背景阴影的透明度,使用dimAmount,数值从0.0 ~ 1.0,数字越小越透明,默认值为0.6

override fun onResume() {
    dialog?.window?.attributes?.dimAmount = 0.6f
}

全屏显示

网上查阅了很多资料,大部分都说要使用style的方式,效果很不错,但是我测试的时候,dimAmount和动画无法使用了,我目前使用以下方法解决全屏的问题,虽然不够完美,但目前来看是最优的方式:

override fun onResume() {
    super.onResume()
    dialog?.window?.setLayout(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT
    )
}

UI刷新

这是一个令人头疼的问题,Fragment创建的时候我们并不知道UI什么时候能绘制完成,如果在创建DialogFragment实例就传参刷新UI,大概率会导致崩溃,既然本质是Fragment,就可以按照对付Fragment的思路去对付DialogFragment

  • 创建一个抽象类,继承DialogFragment
abstract class BaseDialog : DialogFragment{ }
  • 使用LiveData,绑定生命周期
val dialogData = MutableLiveData()
  • 创建一个供外部调用的方法,传入我们需要的数据
fun updateData(data: Any?) {
    dialogData.postValue(data)
}
  • 创建数据回调(Listener方式)
private var dataListener: ((Any?) -> Unit)? = null

override fun onViewCreated(view: View, savedInstanceState: Bundle?){
    super.onViewCreated(view, savedInstanceState)
    dialogData.observe(viewLifecycleOwner) { dataListener?.invoke(it) }
}

fun setOnDataListener(listener: (Any?) -> Unit) {
    this.dataListener = listener
}

//子类中调用监听
setOnDataListener { data ->  // TODO  根据data的数据类型执行不同的UI逻辑 }
  • 创建数据回调(Abstract方式)
abstract fun onUpdate(data: Any?)

override fun onViewCreated(view: View, savedInstanceState: Bundle?){
    super.onViewCreated(view, savedInstanceState)
    dialogData.observe(viewLifecycleOwner) { onUpdate?.invoke(it) }
}

//在子类中重写onUpdate方法
override fun onUpdate(data:Any?){
    //TODO 根据data的数据类型执行不同的UI逻辑
}

小结

DialogFragment乍一看使用起来挺麻烦,但其本质就是一个Fragment,我们基本可以使用对待Fragment的思路去处理问题。
本人能力有限,学识浅薄,只能描述自己遇到的一些问题,如果有写的不好的地方欢迎批评。

补充

注意一点:如果要在DialogFragment中嵌套一个Fragment,需要使用childFragmentManager来添加新的Fragment

工作中要涉及到万恶的旧版本(Api <= 22),设置全屏会显示状态栏,需要修改View的属性:

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
     val window = dialog?.window
     if (window != null) {
     val uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
              View.SYSTEM_UI_FLAG_FULLSCREEN or
              View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
     dialog?.window?.decorView?.systemUiVisibility = uiOptions
     }
}

如果是使用 Api30及其以上,这里会出现很多@Deprecated删除线,不要紧张,新的Api只能在新版中使用,这里可能Studio没有处理。用以上方式可以消除状态栏,但是,弹出dialog的时候,状态栏会闪一下马上消失,暂时没有更完美的解决方法,如果有请留言,感激不尽。

你可能感兴趣的:(Android DialogFragment快速使用方法)