英文:
ViewTreeLifecycleOwner not found from Dialog
问题
当我将以下内容添加到XML中:
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
我遇到了上面的错误。我尝试更新appcompat库,但没有起作用。有人有解决方案吗?
英文:
when I add
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
to XML I am getting above error. I tried to update appcompat library but it didnt worked.Anyone have sollution?
答案1
得分: 1
我还没有找到在基于视图的AlertDialog
中使Compose UI正常工作的方法(无论是平台版本还是AppCompat的变体)。如果你想在对话框样式的组件中使用Compose UI,有两种方法可以使其正常工作。
选项1
如果你的屏幕的UI已经是Compose,可以以声明性的方式使用AlertDialog
组合函数,而无需使用XML:
@Composable
fun MyScreen() {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
TextButton(
text = "OK",
onClick = { showDialog = false },
)
},
title = { /* 在这里放置你的对话框内容... */ },
text = { /* 和/或在这里放置... */ },
)
}
// 屏幕的UI放在这里
Button(onClick = { showDialog = true }) {
Text("点击我显示对话框")
}
}
选项2
如果需要在选项1不适用的情况下显示对话框,可以考虑使用DialogFragment
,而不是基于视图的AlertDialog
类。由于对话框片段是一个Fragment
,它可以访问Compose所需的ViewTreeLifecycleOwner
:
class MyDialogFragment : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): ComposeView {
return ComposeView(requireContext()).also {
it.clipToPadding = false
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(view as ComposeView).setContent {
// 在这里放置你的对话框内容
}
}
}
当需要在屏幕上显示MyDialogFragment
时:
// 来自一个活动
MyDialogFragment().show(this.supportFragmentManager, "dialog-tag")
// 来自一个片段
MyDialogFragment(this.childFragmentManager, "dialog-tag")
英文:
I haven't found a way to make Compose UI work inside a View-based AlertDialog
(neither the platform version nor AppCompat's variant). If you want to use Compose UI in a dialog-like component, there are two ways to make it work.
Option 1
If your screen's UI is Compose already, use the AlertDialog
composable function in a declarative way and skip the need for XML altogether:
@Composable
fun MyScreen() {
var showDialog by remember { mutableStateOf(false) }
if (showDialog) {
AlertDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
TextButton(
text = "OK",
onClick = { showDialog = false },
)
},
title = { /* Your dialog's content here... */ },
text = { /* and/or here... */ },
)
}
// Screen's UI goes here
Button(onClick = { showDialog = true }) {
Text("Click me to show a dialog")
}
}
Option 2
If you need to show the dialog even in scenarios where Option 1 isn't really possible, consider using a DialogFragment
instead of the View-based AlertDialog
class. Since a dialog fragment is a Fragment
, it has access to the ViewTreeLifecycleOwner
that Compose expects:
class MyDialogFragment : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): ComposeView {
return ComposeView(requireContext()).also {
it.clipToPadding = false
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(view as ComposeView).setContent {
// Your dialog's content here
}
}
}
When you need to show MyDialogFragment
on screen:
// From an activity
MyDialogFragment().show(this.supportFragmentManager, "dialog-tag")
// From a fragment
MyDialogFragment(this.childFragmentManager, "dialog-tag")
答案2
得分: 1
你应该将lifecycleOwner
绑定到对话框的根视图上。
ViewTreeLifecycleOwner.set(view, lifecycleOwner)
对于我来说,我在对话框构建器中使用了自定义的Compose视图。
AlertDialog.Builder(context, R.style.my_style) {
setTitle("title")
setMessage("message")
setView(myCustomView)
}.create().apply {
window?.let {
ViewTreeLifecycleOwner.set(it.decorView, activity as LifecycleOwner)
it.decorView.setViewTreeSavedStateRegistryOwner(activity as SavedStateRegistryOwner)
}
}
如果你使用DialogFragment
,我认为你可以在以下位置执行相同的操作。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewTreeLifecycleOwner.set(view, activity as LifecycleOwner)
view.setViewTreeSavedStateRegistryOwner(activity as SavedStateRegistryOwner)
}
英文:
You should bind lifecycleOwner to the root view of the dialog.
ViewTreeLifecycleOwner.set(view, lifecycleOwner)
For me, I use a custom compose view in AlertDialog
from the dialog builder.
AlertDialog.Builder(context, R.style.my_style) {
setTitle("title")
setMessage("message")
setView(myCustomView)
}.create().apply {
window?.let {
ViewTreeLifecycleOwner.set(it.decorView, activity as LifecycleOwner)
it.decorView.setViewTreeSavedStateRegistryOwner(activity as SavedStateRegistryOwner)
}
}
If you use DialogFragment
, I think you could do the same thing in
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ViewTreeLifecycleOwner.set(view, activity as LifecycleOwner)
view.setViewTreeSavedStateRegistryOwner(activity as SavedStateRegistryOwner)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论