使用导航组件在任何目的地弹出常见错误对话框的最佳实践
The best practice to pop up a common error dialog in any destination with navigation component
我想在任何目标片段的 ViewModel
中收到错误时显示错误对话框。
现在,我创建了一个 BaseViewModel
和一个 BaseFragment
来完成这些工作,并使所有 fragments
和 ViewModels
扩展它。
但是很难将所有目的地都连接到对话框的 DialogFragment。
我应该将对话框从 nav_graph.xml
中删除吗?
如果您使用的是 kotlin,则可以使用扩展函数来实现
inline fun Activity.alertDialog(
title: CharSequence? = null,
message: CharSequence? = null,
func: AlertDialogHelper.() -> Unit
) {
val dialogFragment = AlertDialogHelper(this, title, message).apply {
func()
}
val fragmentTransaction = (this as AppCompatActivity).supportFragmentManager.beginTransaction()
fragmentTransaction.let { dialogFragment.show(it, TAG) }
}
inline fun Fragment.alertDialog(
title: CharSequence? = null,
message: CharSequence? = null,
func: AlertDialogHelper.() -> Unit
) {
val dialogFragment = AlertDialogHelper(this.context!!, title, message).apply {
func()
}
val fragmentTransaction = (this).childFragmentManager.beginTransaction()
fragmentTransaction.let { dialogFragment.show(it, TAG) }
}
AlertDialogHelper
是由 DialogFragment
扩展的同一个对话框 class
AlertDialogHelper
class AlertDialogHelper(context: Context, title: CharSequence?, message: CharSequence?) :
DialogFragment() {
private val dialogView: View by lazyFast {
LayoutInflater.from(context).inflate(R.layout.dialog_layout, null)
}
private val title: TextView by lazyFast {
dialogView.findViewById(R.id.dialogInfoTitleTextView)
}
private val message: TextView by lazyFast {
dialogView.findViewById(R.id.dialogInfoMessageTextView)
}
private val positiveButton: Button by lazyFast {
dialogView.findViewById(R.id.dialogInfoPositiveButton)
}
private val negativeButton: Button by lazyFast {
dialogView.findViewById(R.id.dialogInfoNegativeButton)
}
var cancelable: Boolean? = true
init {
this.title.text = title
this.message.text = message
}
fun positiveButton(text: CharSequence, func: (() -> Unit)? = null) {
with(positiveButton) {
this.text = text
setClickListenerToDialogButton(func)
}
}
fun negativeButton(text: CharSequence, func: (() -> Unit)? = null) {
with(negativeButton) {
this.text = text
setClickListenerToDialogButton(func)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return dialogView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
title.goneIfTextEmpty()
message.goneIfTextEmpty()
positiveButton.goneIfTextEmpty()
negativeButton.goneIfTextEmpty()
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
isCancelable = this.cancelable!!
}
override fun onDestroyView() {
super.onDestroyView()
}
private fun TextView.goneIfTextEmpty() {
visibility = if (text.isNullOrEmpty()) {
View.GONE
} else {
View.VISIBLE
}
}
private fun Button.setClickListenerToDialogButton(func: (() -> Unit)?) {
setOnClickListener {
func?.invoke()
dialog?.dismiss()
}
}
fun <T> lazyFast(operation: () -> T): Lazy<T> = lazy(LazyThreadSafetyMode.NONE) {
operation()
}
}
我想在任何目标片段的 ViewModel
中收到错误时显示错误对话框。
现在,我创建了一个 BaseViewModel
和一个 BaseFragment
来完成这些工作,并使所有 fragments
和 ViewModels
扩展它。
但是很难将所有目的地都连接到对话框的 DialogFragment。
我应该将对话框从 nav_graph.xml
中删除吗?
如果您使用的是 kotlin,则可以使用扩展函数来实现
inline fun Activity.alertDialog(
title: CharSequence? = null,
message: CharSequence? = null,
func: AlertDialogHelper.() -> Unit
) {
val dialogFragment = AlertDialogHelper(this, title, message).apply {
func()
}
val fragmentTransaction = (this as AppCompatActivity).supportFragmentManager.beginTransaction()
fragmentTransaction.let { dialogFragment.show(it, TAG) }
}
inline fun Fragment.alertDialog(
title: CharSequence? = null,
message: CharSequence? = null,
func: AlertDialogHelper.() -> Unit
) {
val dialogFragment = AlertDialogHelper(this.context!!, title, message).apply {
func()
}
val fragmentTransaction = (this).childFragmentManager.beginTransaction()
fragmentTransaction.let { dialogFragment.show(it, TAG) }
}
AlertDialogHelper
是由 DialogFragment
AlertDialogHelper
class AlertDialogHelper(context: Context, title: CharSequence?, message: CharSequence?) :
DialogFragment() {
private val dialogView: View by lazyFast {
LayoutInflater.from(context).inflate(R.layout.dialog_layout, null)
}
private val title: TextView by lazyFast {
dialogView.findViewById(R.id.dialogInfoTitleTextView)
}
private val message: TextView by lazyFast {
dialogView.findViewById(R.id.dialogInfoMessageTextView)
}
private val positiveButton: Button by lazyFast {
dialogView.findViewById(R.id.dialogInfoPositiveButton)
}
private val negativeButton: Button by lazyFast {
dialogView.findViewById(R.id.dialogInfoNegativeButton)
}
var cancelable: Boolean? = true
init {
this.title.text = title
this.message.text = message
}
fun positiveButton(text: CharSequence, func: (() -> Unit)? = null) {
with(positiveButton) {
this.text = text
setClickListenerToDialogButton(func)
}
}
fun negativeButton(text: CharSequence, func: (() -> Unit)? = null) {
with(negativeButton) {
this.text = text
setClickListenerToDialogButton(func)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return dialogView
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
title.goneIfTextEmpty()
message.goneIfTextEmpty()
positiveButton.goneIfTextEmpty()
negativeButton.goneIfTextEmpty()
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
isCancelable = this.cancelable!!
}
override fun onDestroyView() {
super.onDestroyView()
}
private fun TextView.goneIfTextEmpty() {
visibility = if (text.isNullOrEmpty()) {
View.GONE
} else {
View.VISIBLE
}
}
private fun Button.setClickListenerToDialogButton(func: (() -> Unit)?) {
setOnClickListener {
func?.invoke()
dialog?.dismiss()
}
}
fun <T> lazyFast(operation: () -> T): Lazy<T> = lazy(LazyThreadSafetyMode.NONE) {
operation()
}
}