前言
现在基本上弹窗都用 DialogFragment 来写了。
其优势很明显(比如拥有生命周期&旋转屏幕不消失等),用起来方便
基本可以淘汰 Dialog 了。
需求
实现
我还是按照之前使用 PopupWindow 的方式写的布局:
父层撑满,内容区居中,并在父层设置半透明遮罩。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_50_000000"
>
<RelativeLayout
android:id="@+id/rl_dialog_task_main"
android:layout_width="@dimen/dim280"
android:layout_height="@dimen/dim204"
android:background="@color/transparent"
android:layout_centerInParent="true">
...
...
</RelativeLayout>
</RelativeLayout>
但是,DialogFragment 的背景色是默认设置的,我设置的背景色,只在内容区显示
如上图,有棱角的半透明黑色,同时因为不规则,不能用圆角背景解决。
解决方案
- 在 onCreateView 中添加 下面两句话,即可
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
- 同时在Xml文件中,不设置背景色
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- android:background="@color/color_50_000000"-->
实现效果
附相关代码
/**
* <pre>
* author : jake
* time : 2018/09/07
* function : 任务详情页弹窗 通用类型
* version: 1.0
* </pre>
*/
abstract class TaskDialog : AppCompatDialogFragment() {
abstract val tips: String
abstract val function: String
private var functionCallback: (() -> Unit)? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val view = inflater.inflate(R.layout.dialog_task, container, false)
view.tv_dialog_tips.text = tips
view.tv_dialog_fun.text = function
view.tv_dialog_cancel.setOnClickListener {
dismiss()
}
view.tv_dialog_fun.setOnClickListener {
dismiss()
functionCallback?.invoke()
}
return view
}
fun show(manager: FragmentManager?, callback: () -> Unit) {
super.show(manager, tips)
this.functionCallback = callback
}
}
想要设置不可取消,点击空白区域也不可取消,可以添加如下属性:
// 设置点击其他区域不可取消
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)
虽然不可取消,但是返回键仍能使其消失,所以要监听 返回键,并拦截点击事件
// 监听返回键
dialog.setOnKeyListener(DialogInterface.OnKeyListener { _, p1, _ ->
if (p1 == KeyEvent.KEYCODE_BACK) {
return@OnKeyListener true
}
false
})
子类
/**
* <pre>
* author : jake
* time : 2018/09/07
* function : 任务详情页弹窗 删除录音
* version: 1.0
* </pre>
*/
class TaskDeleteDialog : TaskDialog() {
override val tips: String
get() = stringForRes(R.string.delete_confirm)
override val function: String
get() = stringForRes(R.string.delete)
}
使用
private val deleteDialog by lazy { TaskDeleteDialog() }
// 设置返回点击监听
iv_task_back.setOnClickListener {
deleteDialog.show(fragmentManager){
activity!!.finish()
}
}
注意,当dialog实例化两次时,会报错闪退,所以在有可能调用两次的地方,添加是否实例化判断
使用 isAdded 方法判断即可
if (!reloginDialog.isAdded) {
reloginDialog.show((ActivityStack.currentActivity() as? AppCompatActivity)?.supportFragmentManager) {
loginOut()
}
}
设置BottomSheetDialogFragment背景透明(2020.3.3)
设置如下代码竟然无效:
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
改为如下代码即可:
(view?.parent as? View)?.setBackgroundResource(R.color.transparent)
附部分代码:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return LayoutInflater.from(context).inflate(R.layout.dialog_select_course, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
(view?.parent as? View)?.setBackgroundResource(R.color.transparent)
text_title.typeface = Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD)