ViewTreeLifecycleOwner not found from Dialog.

huangapple go评论52阅读模式
英文:

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)
}

huangapple
  • 本文由 发表于 2023年2月19日 21:32:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/75500480.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定