目录
一、Dialog和DialogFragment的区别
Android在DialogFragment推出后,就已经不推荐继续使用Dialog,可替换为DialogFragment:
- 更好的生命周期管理:DialogFragment能够自动处理Activity的生命周期事件,确保对话框在Activity重建时能够正确恢复。在Activity退出的时候会自动回收Dialog弹窗。
- 更高的灵活性:DialogFragment支持复杂的UI和逻辑操作,能够满足更多样化的需求。
- 更好的封装性:通过封装对话框的显示逻辑,DialogFragment提高了代码的可重用性和可维护性。
- 更好的用户体验:由于DialogFragment能够更好地处理配置更改,因此能够提供更稳定、更流畅的用户体验。
二、Dialog如何使用?
(1)如下是一个最简单的使用方法:
Dialog(this@SettingActivity).show()
(2)当然,我们不可能这样使用,而是会增加布局视图、动画:
<!-- res/layout/dialog_custom.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/textViewMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是一个自定义对话框"
android:textSize="18sp" />
<Button
android:id="@+id/buttonOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定" />
</LinearLayout>
// 假设这是Activity中的一个方法
fun showCustomDialog() {
// 创建一个Dialog实例
val dialog = Dialog(this)
// 去除Dialog的标题
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
// 设置Dialog的内容布局
dialog.setContentView(R.layout.dialog_custom)
// 设置Dialog的窗口动画(需要先在res/values/styles.xml中定义动画样式)
//dialog.window?.setWindowAnimations(R.style.DialogAnimation)
// 获取布局中的组件并设置事件监听器
val textViewMessage = dialog.findViewById<TextView>(R.id.textViewMessage)
val buttonOk = dialog.findViewById<Button>(R.id.buttonOk)
// 设置按钮的点击事件监听器
buttonOk.setOnClickListener {
// 关闭Dialog
dialog.dismiss()
}
// 显示Dialog
dialog.show()
}
(3)那么如何继承dialog来自定一个dialog呢?
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import android.widget.Button
import android.widget.TextView
// 自定义Dialog类
class CustomDialog(context: Context) : Dialog(context) {
// 布局中的组件
private lateinit var textViewMessage: TextView
private lateinit var buttonOk: Button
//Dialog的初始化其实就是让我们去初始化自己的视图
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 去除标题
requestWindowFeature(Window.FEATURE_NO_TITLE)
// 设置内容布局
setContentView(R.layout.dialog_custom)
// 初始化布局中的组件
textViewMessage = findViewById(R.id.textViewMessage)
buttonOk = findViewById(R.id.buttonOk)
// 设置按钮的点击事件监听器
buttonOk.setOnClickListener {
// 关闭Dialog
dismiss()
}
// (可选)设置Dialog的窗口动画
// window?.setWindowAnimations(R.style.DialogAnimation)
}
// 你可以添加更多的方法和属性来扩展你的Dialog
// 例如,一个方法来设置消息文本
fun setMessage(message: String) {
textViewMessage.text = message
}
}
// 在你的Activity或Fragment中这样使用它
fun showCustomDialog(context: Context) {
val customDialog = CustomDialog(context)
// (可选)设置消息文本
customDialog.setMessage("这是一个自定义对话框")
// 显示Dialog
customDialog.show()
}
这个CustomDialog类直接继承了Dialog,并在其onCreate方法中设置了布局、初始化了组件,并设置了监听器。show()其实就是走Dialog的生命周期,然后做初始化工作,注意,show()之后才执行onCreate()。如下源码可以看出:
三、Dialog是什么,Window又是什么?
我们可以看一下Dialog的源码。
Dialog的构造方法中可以看出,Dialog实质上是个Window。
Dialog是Android中用于显示一个浮动窗口的类,这个窗口会覆盖在当前的活动(Activity)或应用程序的顶部。Dialog用于临时显示一些信息给用户,或者要求用户进行某些选择(如确认、选择列表项等)。Dialog可以包含各种控件,如按钮、文本输入框、列表视图等,以便与用户进行交互。
那么Window是什么?
Window是Android中更为抽象的一个概念,它代表了屏幕上的一块矩形区域,用于显示内容。在Android中,几乎所有的UI组件都是基于Window的,包括Activity、Dialog等。Activity实际上是一个特殊的Window,它拥有整个屏幕作为显示区域,并且可以在其上添加各种视图(Views)来构建用户界面。
Dialog与Window的区别:
Dialog与Window:Dialog内部通过PhoneWindow来实现窗口的显示,PhoneWindow是Window的具体实现类。Dialog在创建时会关联一个PhoneWindow对象,并通过这个对象来管理窗口的视图和布局。
WindowManager 是什么?
还有一个WindowManager,WindowManager负责将应用的用户界面显示在屏幕上,并管理窗口的创建、显示、隐藏、更新等操作。Dialog在创建时会关联一个Context(上下文),并通过这个Context获取WindowManager服务,进而与WindowManager绑定,实现窗口的添加和管理。
四、DialogFragment是什么?
DialogFragment 本质上是一个Fragment + Dialog,也就具有Fragment所拥有的生命周期,同时拥有Dialog的特点;在使用时,更容易通过生命周期回调来管理弹窗,对于复杂样式的弹窗,使用DialogFragment更加方便和高效。
五、DialogFragment如何使用
(1)创建xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="880dp"
android:layout_height="420dp"
android:layout_gravity="center"
android:background="@drawable/home_rectangle_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/home_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:text="是否立即关机?"
android:textColor="#576478"
android:textSize="42sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_start_dev"
android:layout_width="260dp"
android:layout_height="100dp"
android:gravity="center"
android:text="立即开机"
android:layout_marginTop="70dp"
android:textSize="42sp"
android:textColor="@color/white"
android:background="@drawable/home_rectangle_blue_background"
app:layout_constraintEnd_toStartOf="@+id/backstage_guideline"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/home_textview" />
<TextView
android:id="@+id/tv_back"
android:layout_width="260dp"
android:layout_height="100dp"
android:layout_marginTop="70dp"
android:gravity="center"
android:textColor="#569DF6"
android:text="取消"
android:textSize="42sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/backstage_guideline"
app:layout_constraintTop_toBottomOf="@+id/home_textview" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/backstage_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
(2)创建一个类继承自DialogFragment,然后给他指定布局文件
在 onCreateView() 方法中,加载弹窗的布局文件。
在 onViewCreated() 方法中,初始化弹窗的控件。
class MyDialogFragment: DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
dialog?.requestWindowFeature(Window.FEATURE_NO_TITLE)
var view :View = inflater.inflate(R.layout.backstage_dialog_devonoff,container)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var tv :TextView= view.findViewById(R.id.tv_start_dev)
}
}
(3)在Activity中进行使用。
val myDialogFragment: MyDialogFragment= MyDialogFragment()
myDialogFragment.show(supportFragmentManager, "MyDialogFragment")
六、DialogFragment源码解析
DialogFragment创建的时候,会有两个创建方法:onCreateDialog和onCreateView
class MyDialogFragment:DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
}
如果你在onCreateDialog和onCreateView都写了布局,那么会优先使用onCreateDialog里面的。源码这里我们可以看到。如果onCreateDialog不传递一个新的dialog,那么就会使用默认的,而布局,就是从onCreateView里面取,也就是requireView方法。
如果onCreateDialog不重写,会自动创建一个空白的dialog。view使用的就是oncreateView的:如下: