一、DialogFragment 简介
DialogFragment 是 Android 中的一个特殊的 Fragment,通常用于创建和显示弹窗。DialogFragment 继承自 Fragment,因此具有 Fragment 的所有特性。
DialogFragment 的使用非常简单,只需要如下几步:
- 创建 DialogFragment 的子类。
- 在
onCreateView()
方法中,加载弹窗的布局文件。 - 在
onViewCreated()
方法中,初始化弹窗的控件。 - 使用
show()
方法显示弹窗。
以下是一个简单的 DialogFragment 示例:
java
public class SimpleDialogFragment extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_simple_dialog, container, false);
return view;
}
}
fragment_simple_dialog.xml
布局文件如下:
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="500dp"
android:gravity="center"
android:text="测试弹窗"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
要使用该示例,需要在 Activity
中添加以下代码:
java
// 创建弹窗实例
SimpleDialogFragment dialogFragment = new SimpleDialogFragment();
// 显示弹窗
dialogFragment.show(getSupportFragmentManager(), "SimpleDialogFragment");
该代码将创建一个 SimpleDialogFragment
实例,并使用 show()
方法显示弹窗。
二、几个小问题的解法
问题1:弹窗宽度设置为 match_parent 没有效果
明明我的布局里面设置的 layout_width
是 match_parent
,但是运行起来发现弹窗的内容宽度却是 wrap_content
的效果。运行效果如下图这样拉跨:
原因是当我们以布局 View 创建 DialogFragment 时。在 View 添加后,对话框最外层的 ViewGroup 并不知道我们导入的 View 所需要的的宽度(也就是说在 在 onCreateView 和 onViewCreated 方法里都不知道需要宽度)。
所以我们需要在 onStart
生命周期里修改一下对话框尺寸参数。
解决方案:
kotlin
class SimpleDialogFragment : DialogFragment(){
companion object {
const val TAG = "SimpleDialogFragment"
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.layout_simple_dialog_fragment, container, false)
}
override fun onStart() {
super.onStart()
val window = dialog?.window
// 设置宽度为铺满
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
}
问题2:如何设置弹窗布局内容位于屏幕底部
kotlin
class SimpleDialogFragment : DialogFragment(){
companion object {
const val TAG = "SimpleDialogFragment"
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.layout_simple_dialog_fragment, container, false)
}
override fun onStart() {
super.onStart()
val window = dialog?.window
// 设置宽度为铺满
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
// 设置布局内容显示在底部
window?.setGravity(Gravity.BOTTOM)
}
}
问题3:弹窗四周默认的 padding 如何去掉
在经过上面两步设置后,基本满足我们的要求了,不过还有点小瑕疵,在弹窗四周还有一个默认的 padding 🤪:
解决方案如下:
首先,创建一个自定义的样式,去掉 padding。在 res/values/styles.xml 文件中,添加如下代码:
xml
<style name="DialogFragmentNoPaddingStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:paddingLeft">0dp</item>
<item name="android:paddingRight">0dp</item>
<item name="android:paddingTop">0dp</item>
<item name="android:paddingBottom">0dp</item>
</style>
然后,在 DialogFragment 的 onCreate() 方法中,设置该样式:
kotlin
class SimpleDialogFragment : DialogFragment(){
companion object {
const val TAG = "SimpleDialogFragment"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置 Style
setStyle(STYLE_NO_FRAME, R.style.DialogFragmentNoPaddingStyle)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.layout_simple_dialog_fragment, container, false)
}
override fun onStart() {
super.onStart()
val window = dialog?.window
// 设置宽度为铺满
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
// 设置布局内容显示在底部
window?.setGravity(Gravity.BOTTOM)
}
}
运行效果如下:
(完)