Kotlin 基于DialogFragment封装的通用Dial
2021-01-02 本文已影响0人
爱上这阳光
一、背景
Dialog是项目中最常用的功能之一,为了减少在xml中重复定义底部两个按钮,所以在参考Android基于DialogFragment封装一个通用的Dialog的基础上使用Kotlin重写了BaseDialog。
二、相关源码:
BaseDialog.kt
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.view.*
import androidx.annotation.LayoutRes
import androidx.annotation.StyleRes
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import kotlinx.android.synthetic.main.dialog_base.*
class BaseDialog() : DialogFragment() {
companion object {
const val BASE_DIALOG_TAG = "BASE_DIALOG"
private var mFragment: FragmentManager? = null
private var mBuildMethod: ((Dialog?, View?) -> Unit)? = null
private var mDismissMethod: (() -> Unit)? = null
private var mNegativeButtonMethod: ((Dialog?, View?) -> Unit)? = null
private var mPositiveButtonMethod: ((Dialog?, View?) -> Unit)? = null
}
private var mLayoutRes: Int = 0
private var mWidth: Int = 0
private var mHeight: Int = 0
private var mAnimRes: Int = 0
private var mTitle: String? = null
private var mContent: String? = null
private var mMessage: String? = null
private var mNegativeToDismiss = true
private var mCanceledOnTouchOutside = false
private var mBuildMethodAdded = false
private var mDismissMethodAdded = false
private var mNegativeButtonMethodAdded = false
private var mPositiveButtonMethodAdded = false
private val mButtonHandler =
View.OnClickListener { view ->
if (view === btn_dialog_cancel) {
if (mNegativeToDismiss) dismiss()
if (mNegativeButtonMethodAdded) {
mNegativeButtonMethod?.run {
invoke(dialog, getBaseView())
}
}
} else if (view === btn_dialog_ok) {
if (mPositiveButtonMethodAdded) {
mPositiveButtonMethod?.run {
invoke(dialog, getBaseView())
}
}
}
}
init {
arguments = Bundle()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.run {
mLayoutRes = getInt("mLayoutRes")
mWidth = getInt("mWidth")
mHeight = getInt("mHeight")
mTitle = getString("mTitle")
mContent = getString("mContent")
mMessage = getString("mMessage")
mNegativeToDismiss = getBoolean("mNegativeToDismiss", true)
mCanceledOnTouchOutside = getBoolean("mCanceledOnTouchOutside")
mBuildMethodAdded = getBoolean("mBuildMethodAdded")
mDismissMethodAdded = getBoolean("mDismissMethodAdded")
mNegativeButtonMethodAdded = getBoolean("mNegativeButtonMethodAdded")
mPositiveButtonMethodAdded = getBoolean("mPositiveButtonMethodAdded")
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.dialog_base, container, false)
if (mLayoutRes > 0) {
val contentView = inflater.inflate(mLayoutRes, null, false)
(view.findViewById(R.id.ll_dialog_custom) as ViewGroup).addView(contentView, 0)
}
isCancelable = true
dialog?.run {
setCanceledOnTouchOutside(mCanceledOnTouchOutside)
}
if (mBuildMethodAdded) {
mBuildMethod?.run {
invoke(dialog, view)
}
}
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val showTitle = !TextUtils.isEmpty(mTitle)
val showContent = !TextUtils.isEmpty(mContent)
val showMessage = !TextUtils.isEmpty(mMessage)
if (showTitle) {
tv_dialog_title.text = mTitle
tv_dialog_title_only.text = mTitle
}
if (showContent) {
tv_dialog_content.text = mContent
tv_dialog_title.visibility = if (showTitle) View.VISIBLE else View.GONE
} else {
tv_dialog_title_only.visibility = if (showTitle) View.VISIBLE else View.GONE
}
if (showMessage) tv_dialog_message.text = mMessage
tv_dialog_content.visibility = if (showContent) View.VISIBLE else View.GONE
tv_dialog_message.visibility = if (showMessage) View.VISIBLE else View.GONE
btn_dialog_cancel.setOnClickListener(mButtonHandler)
btn_dialog_ok.setOnClickListener(mButtonHandler)
}
override fun onStart() {
super.onStart()
val dialog = dialog ?: return
val window = dialog.window ?: return
val params = window.attributes
// 设置背景色透明
window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
// 设置Dialog动画效果
if (mAnimRes > 0) window.setWindowAnimations(mAnimRes)
// 设置Dialog的宽度
if (mWidth > 0) params.width = mWidth
// 设置Dialog的高度
if (mHeight > 0) params.height = mHeight
// 设置屏幕透明度 0.0f~1.0f(完全透明~完全不透明)
params.dimAmount = 0.4f
params.gravity = Gravity.CENTER
window.attributes = params
}
override fun dismiss() {
if (fragmentManager == null) return
super.dismissAllowingStateLoss()
}
override fun onDestroy() {
if (mDismissMethodAdded) {
mDismissMethod?.run {
invoke()
}
}
super.onDestroy()
}
private fun getBaseView(): View? {
return view
}
fun setFragmentManager(fragment: FragmentManager): BaseDialog {
mFragment = fragment
return this
}
fun setDialogView(@LayoutRes layoutRes: Int): BaseDialog {
mLayoutRes = layoutRes
arguments?.putInt("mLayoutRes", mLayoutRes)
return this
}
fun setWindowSize(width: Int, height: Int): BaseDialog {
setWidth(width)
setHeight(height)
return this
}
fun setWidth(width: Int): BaseDialog {
mWidth = width
arguments?.putInt("mWidth", mWidth)
return this
}
fun setHeight(height: Int): BaseDialog {
mHeight = height
arguments?.putInt("mHeight", mHeight)
return this
}
fun setAnimStyle(@StyleRes animStyle: Int): BaseDialog {
mAnimRes = animStyle
arguments?.putInt("mAnimRes", mAnimRes)
return this
}
fun setTitle(title: String): BaseDialog {
mTitle = title
arguments?.putString("mTitle", mTitle)
return this
}
fun setContent(content: String): BaseDialog {
mContent = content
arguments?.putString("mContent", mContent)
return this
}
fun setMessage(message: String): BaseDialog {
mMessage = message
arguments?.putString("mMessage", mMessage)
return this
}
fun setNegativeToDismiss(negativeToDismiss: Boolean): BaseDialog {
mNegativeToDismiss = negativeToDismiss
arguments?.putBoolean("mNegativeToDismiss", mNegativeToDismiss)
return this
}
fun setCanceledOnTouchOutside(canceledOnTouchOutside: Boolean): BaseDialog {
mCanceledOnTouchOutside = canceledOnTouchOutside
arguments?.putBoolean("mCanceledOnTouchOutside", mCanceledOnTouchOutside)
return this
}
fun setBuildMethod(buildMethod: (Dialog?, View?) -> Unit): BaseDialog {
mBuildMethod = buildMethod
arguments?.putBoolean("mBuildMethodAdded", true)
return this
}
fun setDismissMethod(dismissMethod: () -> Unit): BaseDialog {
mDismissMethod = dismissMethod
arguments?.putBoolean("mDismissMethodAdded", true)
return this
}
fun setNegativeButtonMethod(negativeButtonMethod: (Dialog?, View?) -> Unit): BaseDialog {
mNegativeButtonMethod = negativeButtonMethod
arguments?.putBoolean("mNegativeButtonMethodAdded", true)
return this
}
fun setPositiveButtonMethod(positiveButtonMethod: (Dialog?, View?) -> Unit): BaseDialog {
mPositiveButtonMethod = positiveButtonMethod
arguments?.putBoolean("mPositiveButtonMethodAdded", true)
return this
}
fun show() {
mFragment?.let {
val ft = it.beginTransaction()
try {
val cls: Class<*> = DialogFragment::class.java
val mDismissed = cls.getDeclaredField("mDismissed")
mDismissed.isAccessible = true
mDismissed[this] = false
val mShownByMe = cls.getDeclaredField("mShownByMe")
mShownByMe.isAccessible = true
mShownByMe[this] = true
} catch (e: Exception) {
super.show(ft, BASE_DIALOG_TAG)
return
}
val prev = it.findFragmentByTag(BASE_DIALOG_TAG)
if (prev != null) {
ft.remove(prev)
}
ft.add(this, BASE_DIALOG_TAG)
ft.commitAllowingStateLoss()
}
}
}
dialog_base.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="@drawable/shape_bg_dialog_base"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="15dp">
<TextView
android:id="@+id/tv_dialog_title_only"
android:layout_width="match_parent"
android:layout_height="48dp"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="订单提交成功"
android:textColor="#333"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_dialog_title"
android:layout_width="match_parent"
android:layout_height="52dp"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="订单提交成功"
android:textColor="#333"
android:textSize="18sp"
android:visibility="gone" />
<TextView
android:id="@+id/tv_dialog_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="我们将在30分钟处理,稍后通知您订单结果!感谢您选择"
android:textColor="#666"
android:textSize="16sp"
android:visibility="gone" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_dialog_custom"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tv_dialog_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:lineSpacingExtra="6dp"
android:minHeight="56dp"
android:text="订单提交成功"
android:textColor="#292d33"
android:textSize="17sp"
android:visibility="gone" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="15dp"
android:background="@color/dividerColor" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="52dp">
<Button
android:id="@+id/btn_dialog_cancel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_bg_dialog_base_btn_cancel"
android:gravity="center"
android:stateListAnimator="@null"
android:text="@android:string/cancel"
android:textColor="#999"
android:textSize="16sp" />
<View
android:layout_width="0.5dp"
android:layout_height="match_parent"
android:background="@color/dividerColor" />
<Button
android:id="@+id/btn_dialog_ok"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/selector_bg_dialog_base_btn_ok"
android:gravity="center"
android:stateListAnimator="@null"
android:text="@android:string/ok"
android:textColor="#393f50"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
shape_bg_dialog_base.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners android:radius="8dp" />
</shape>
selector_bg_dialog_base_btn_ok.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="#FFF"></solid>
<corners android:bottomRightRadius="8dp" />
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="#F0F0F0" />
<corners android:bottomRightRadius="8dp" />
</shape>
</item>
</selector>
selector_bg_dialog_base_btn_cancel.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="#FFF"></solid>
<corners android:bottomLeftRadius="8dp" />
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="#F0F0F0" />
<corners android:bottomLeftRadius="8dp" />
</shape>
</item>
</selector>
三、使用文档
1、使用内置样式:
BaseDialog()
.setFragmentManager(supportFragmentManager)
.setMessage("确定删除?")
.setCanceledOnTouchOutside(true) // 点击dialog外部关闭dialog
.setDismissMethod { // Dialog消失回调
...
}
.setPositiveButtonMethod { dialog, view -> // 点击底部右侧按钮回调
dialog?.dismiss()
...
}
.show()
2、加入自定义样式:
BaseDialog()
.setFragmentManager(supportFragmentManager)
.setTitle("添加xx")
.setDialogView(R.layout.dialog_xx)
.setWindowSize(800, 600)
.setBuildMethod { _, view -> // DialogFragment onCreateView方法时回调
view?.run {
findViewById<EditText>(R.id.xx).setText("")
...
}
}
.setNegativeToDismiss(false) // 取消点击底部左侧按钮自动关闭dialog
.setNegativeButtonMethod { dialog, view -> // 点击底部左侧按钮回调
...
dialog?.dismiss()
}
.show()