《Android编程权威指南》之对话框

《Android编程权威指南》第13章了,开始实践编写对话框了。弹出对话框给crime修改记录日期。

关于对话框介绍:https://developer.android.com/guide/topics/ui/dialogs?hl=zh-cn

一、创建DialogFragment

推荐将 DatePickerDialog 封装在 DialogFragment(Fragment的子类)实例中进行使用。这样设备发生改变,比如旋转,对话框还可以重建起来,否则,它就消失啦。

创建 DatePickerFragment,继承 DialogFragment,在里面创建并配置显示DatePickerDialog,将它交给 MainActivity 托管。

由MainActivity托管的两个fragment对象
class DatePickerFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val calendar = Calendar.getInstance()
        val initialYear = calendar.get(Calendar.YEAR)
        val initialMonth = calendar.get(Calendar.MONTH)
        val initialDay = calendar.get(Calendar.DAY_OF_MONTH)

        return DatePickerDialog(requireContext(), null, initialYear, initialMonth, initialDay)
    }
}

}

CrimeFragment.kt中给时间按钮添加点击事件:

        mBinding.btnCrimeDate.setOnClickListener {
            DatePickerFragment().show([email protected], DIALOG_DATE)
        }

在apply函数块里,this引用的是外部的DatePickerFragment,因此,这里要加this关键字。

效果

二、fragment间的数据传递

现需要做同一个activity托管的两个fragment之间传递数据。

CrimeFragment与DatePickerFragment间的对话

在 DatePickerFragment 里面新建 newInstance(Date) 函数,再声明一个以新日期为参数的回调接口函数。

CrimeFragment和DatePickerFragment间的事件流
  • 传递数据给 DatePickerFragment
private const val ARG_DATE = "date"

class DatePickerFragment : DialogFragment() {

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val date = arguments?.getSerializable(ARG_DATE) as Date
        val calendar = Calendar.getInstance()
        calendar.time = date
        val initialYear = calendar.get(Calendar.YEAR)
        val initialMonth = calendar.get(Calendar.MONTH)
        val initialDay = calendar.get(Calendar.DAY_OF_MONTH)

        return DatePickerDialog(requireContext(), null, initialYear, initialMonth, initialDay)
    }

    companion object {
        fun newInstance(date: Date): DatePickerFragment {
            val args = Bundle().apply {
                putSerializable(ARG_DATE, date)
            }
            return DatePickerFragment().apply {
                arguments = args
            }
        }
    }
}

CrimeFragment中按钮点击事件:

        mBinding.btnCrimeDate.setOnClickListener {
            DatePickerFragment.newInstance(mCrime.date).show([email protected], DIALOG_DATE)
        }
  • 返回数据给CrimeFragment
class DatePickerFragment : DialogFragment(){

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        val dateListener = DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
            val resultDate:Date = GregorianCalendar(year,month,dayOfMonth).time
            targetFragment?.let {
                fragment -> (fragment as Callbacks).onDateSelected(resultDate)
            }
        }

       ...

        return DatePickerDialog(requireContext(), dateListener, initialYear, initialMonth, initialDay)
    }
    ...
    interface Callbacks {
        fun onDateSelected(date: Date)
    }
}

OnDateSetListener 能够获取到用户选择的新日期。第一个参数是指确定日期的DatePicker。这里不需要用它,所以用了一个做名字。表示不使用的参数,是一个 Kotlin 编码约定。

上面还设计到了安全调用操作符的 let 函数,有关 Kotlin 作用域函数请参考:https://www.kotlincn.net/docs/reference/scope-functions.html
let 经常用于仅使用非空值执行代码块。

private const val REQUEST_DATE = 0

class CrimeFragment : Fragment(),DatePickerFragment.Callbacks {
...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
       ...
        mBinding.btnCrimeDate.setOnClickListener {
            DatePickerFragment.newInstance(mCrime.date).apply {
                setTargetFragment(this@CrimeFragment, REQUEST_DATE)
                show([email protected], DIALOG_DATE)
            }
        }
    }
...
    override fun onDateSelected(date: Date) {
        mCrime.date = date
        updateUI()
    }
}

三、挑战练习:时间选择对话框

有关「选择器」的官方介绍:https://developer.android.com/guide/topics/ui/controls/pickers?hl=zh-cn

其实是跟 DatePickerDialog 用法一样的,具体参考示例代码啦!

四、其他

CriminalIntent 项目 Demo 地址:
https://github.com/visiongem/AndroidGuideApp/tree/master/CriminalIntent

你可能感兴趣的:(《Android编程权威指南》之对话框)