对话框是提示用户做出决定或输入额外事件的小窗口。对话框不会填充屏幕,通常用于需要用户采取行动才能继续执行的模式事件。
Dialog类是对话框的基类,我们可以使用Dialog来构建一个对话框。但Android建议避免直接使用Dialog,而应该使用其子类。下面是一些Dialog的子类实现:
AlertDialog一个可以显示标题,可选项列表或自定义布局,最多还可以显示三个按钮的对话框。
DatePickerDialog或TimerPickerDialog一个带有允许用户选择日期或时间的预定义UI的对话框。
构建一个简单的提醒对话框
AlertDialog.Builder(this).apply {setTitle("我是标题")setMessage("我是内容")setPositiveButton("确认") { dialog, _ ->//点击了确认按钮dialog.dissmiss()}setNegativeButton("取消") { dialog, _ ->//点击了取消按钮dialog.dismiss()}create()show()
}
上面的对话框包括三个区域:
1.标题区域,这是一个可选项,只应在内容区域被详细消息,列表,或自定义布局占据时使用。如果显示的是一条简单的消息或问题,则不需要标题。
2.内容区域,它可以显示消息,列表,或其他自定义的布局。
3.操作按钮,一个对话框中最多只允许存在三个操作按钮。
构建一个单选列表对话框
val colors = arrayOf("黄色", "红色", "绿色")
AlertDialog.Builder(this).apply {setTitle("选择颜色")setItems(colors) { _, which ->//which 选择项的索引位置}create()show()
}
使用setItems()方法创建一个包含标题和列表的对话框,默认状态下,触摸列表会清除对话框。
构建永久性的单选多选对话啊框
上面的单选对话框默认在触摸列表后清除,要想添加永久性的单选或多选可以分别使用setSingleChoiceItems()或setMultiChoiceItems()方法。setSingleChoiceItems()方法中的第二个参数表示表示默认选中,如果不希望默认选中可传入-1。
val colors = arrayOf("Red", "Green", "Blue")
AlertDialog.Builder(this).apply {setTitle("选择颜色")setSingleChoiceItems(colors, -1) { _, which ->//每次选中一个选项时都会调用该方法//which 选择项的索引位置}setPositiveButton("确定") { dialog, _ ->//点击了确认按钮dialog.dismiss()}setNegativeButton("取消") { dialog, _ ->//点击了取消按钮dialog.dismiss()}create()show()
}
val selectedColors = ArrayList<String>()
val colors = arrayOf("Red", "Green", "Blue")
AlertDialog.Builder(this).apply {setTitle("选择颜色")setMultiChoiceItems(colors, null) { _, which, isChecked ->if (isChecked) {selectedColors.add(colors[which])} else if (selectedColors.contains(colors[which])) {selectedColors.remove(colors[which])}}setPositiveButton("确定") { dialog, _ ->//点击了确认按钮dialog.dismiss()}setNegativeButton("取消") { dialog, _ ->//点击了取消按钮dialog.dismiss()}create()show()
}
构建自定义布局的对话框
构建自定义布局的对话框需要创建一个布局,在调用setView()将其添加到AlertDialog。
res/layout./dialog_signin.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid:src="@drawable/ic_launcher"android:layout_width="match_parent"android:layout_height="64dp"android:scaleType="center"android:background="#FFFFBB33"android:contentDescription="@string/app_name" /><EditTextandroid:id="@+id/username"android:inputType="textEmailAddress"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="16dp"android:layout_marginLeft="4dp"android:layout_marginRight="4dp"android:layout_marginBottom="4dp"android:hint="username" /><EditTextandroid:id="@+id/password"android:inputType="textPassword"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="4dp"android:layout_marginLeft="4dp"android:layout_marginRight="4dp"android:layout_marginBottom="16dp"android:fontFamily="sans-serif"android:hint="password"/></LinearLayout>
val view = layoutInflater.inflate(R.layout.dialog_signin, null)
val etUserName = view.findViewById<View>(R.id.username) as EditText
val etPassword = view.findViewById<View>(R.id.password) as EditText
AlertDialog.Builder(this).apply {setView(view)setPositiveButton("确定") { dialog, _ ->val userName = etUserName.text.toString()val passWord = etPassword.text.toString()//点击了确认按钮dialog.dismiss()}setNegativeButton("取消") { dialog, _ ->//点击了取消按钮dialog.dismiss()}create()show()
}
使用DialogFragment
DialogFragment是Android3.0添加的。谷歌建议应该将DialogFragment用于对话框的容器。DialogFragment提供了创建对话框和管理器外观所需的所有控件,而不用去调用Dialog对象上的方法。使用DialogFragment能正确处理其生命周期的事件。如屏幕旋转。
DialogFragment的使用也很简单,只需继承DialogFragment并实现onCreateDialog()方法。
class MyDialogFragment : DialogFragment() {override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {AlertDialog.Builder(requireActivity()).apply {setMessage("我的DialogFragment")setPositiveButton("确定") { dialog, _ ->dialog.dismiss()}setNegativeButton("取消") { dialog, _ ->dialog.dismiss()}return create()}}
}
然后获取此类的实例并调用show()方法,并传递一个FragmentManager和一个标记名称,该名称是系统在必要时用于恢复该片段的唯一标志。
如何与宿主Activity通信
我们在使用DialogFragment时,通常会与宿主Activity或Fragment分开创建。这时,当我们点击了dialog上的按钮时,DialogFragment可能会自行执行必要操作,但通常需要把事件传递给打开该对话框的Activity或Fragment。我们可以在DialogFragment里面定义一个接口,其中每种类型的点击事件定义一个方法。(当然,你也可以只定义其中的一种)。在打开该对话框的Activity或Fragment实线该接口。
class MyDialogFragment : DialogFragment() {internal lateinit var listener: MyDialogListenerinterface NoticeDialogListener {fun onDialogPositiveClick(dialog: DialogFragment)}override fun onAttach(context: Context) {super.onAttach(context)try {listener = context as NoticeDialogListener} catch (e: ClassCastException) {throw ClassCastException((context.toString() +" must implement MyDialogListener"))}}
}
该调用cancel()还是dismiss()
这两个方法都可以用来清除对话框。系统会在用户触摸某个对话框列表项时清除对话框,但是使用单选按钮和复选按钮时除外,我们应该通过调用dismiss()方法手动清除对话框,如果需要在对话框消失时做一些特定的操作,可以在我们自己DialogFragment中实现onDismiss()方法。
取消对话框是一个特殊事件,它表示用户显示离开对话框,而不完成任务。如用户点击了返回按钮,触摸了对话框外面的区域,或者我们自己显示的调用了cancel()(例如响应对话框中的取消按钮),就会发生这种状况。
系统会在调用了onCancel()回调事件时立即调用onDismiss()。而调用dismiss(),系统会回调onDismiss()而不会调用onCancel()。因此,当用户在对话框中按确定按钮时,应该调用dismiss()方法清除对话框。
自定义对话框的位置和弹出动画
当我们需要一个从底部弹出的对话框时就可以自定义一个。我们继承一个DialogFragment,并重写它的onStart()方法。
override fun onStart() {super.onStart()val window = dialog.window//为window设置一个背景,如果不设置,dialog会与四周有一定的距离window?.setBackgroundDrawableResource(android.R.color.white)//设置window的弹出动画window?.setWindowAnimations(R.style.BottomDialogAnim)//设置window的位置,大小val params = window?.attributesparams?.gravity = Gravity.BOTTOMparams?.width = WindowManager.LayoutParams.MATCH_PARENTparams?.height = WindowManager.LayoutParams.WRAP_CONTENTwindow?.attributes = params
}
进入动画
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"android:fromYDelta="100%"android:toYDelta="0"android:duration="350">
</translate>
退出动画
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"android:fromYDelta="0"android:toYDelta="100%"android:duration="300">
</translate>
Style
<style name="BottomDialogAnim"><item name="android:windowEnterAnimation">@anim/dialog_fr_in</item><item name="android:windowExitAnimation">@anim/dialog_fr_out</item>
</style>














