I have a non compose view that needs to show a BottomSheetDialog. I would like the root view:
myBottomSheetDialog = BottomSheetDialog(requireActivity(), R.style.Theme_Design_BottomSheetDialog)
val bottomSheetView = BottomsheetBinding.inflate(layoutInflater, null, false)
myBottomSheetDialog.setContentView(bottomSheetView.root)
Where the BottomSheetBinding view is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/bottom_sheet_compose"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.compose.ui.platform.ComposeView>
</RelativeLayout>
When I open the dialog the following exception is thrown.
java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.FrameLayout{ee8d547 V.E...... ......I. 0,0-0,0 #7f0a00c1 app:id/container}
at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:244)
at androidx.compose.ui.platform.WindowRecomposer_androidKt.access$createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:1)
at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer(WindowRecomposer.android.kt:99)
at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposer.android.kt:155)
at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:230)
at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(ComposeView.android.kt:244)
at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:251)
at androidx.compose.ui.platform.AbstractComposeView.onMeasure(ComposeView.android.kt:288
For a few reasons I cannot make the parent view compose first. But I would like to show a dialog and use compose for the content within that dialog.
In order to use Composables as content of any window we must set view tree owners on the root of the view tree. In most of the android main classes it's done by google devs already, but for some reason they forgot about BottomSheetDialog.
Here is the solution, call setViewTreeOwners() before calling BottomSheetDialog.setContentView()
private fun setViewTreeOwners() {
val activity = extractActivity(context) // if you have activity present nearby, then just use your activity here.
val decorView = window?.decorView
if (activity != null && decorView != null) {
ViewTreeLifecycleOwner.set(decorView, activity as? LifecycleOwner)
ViewTreeViewModelStoreOwner.set(decorView, activity as? ViewModelStoreOwner)
ViewTreeSavedStateRegistryOwner.set(decorView, activity as? SavedStateRegistryOwner)
}
}
Optional code for extracting activity from context
private fun extractActivity(context: Context?): Activity? {
var currentContext = context
while (currentContext != null) {
if (currentContext is Activity) return currentContext
if (currentContext !is ContextWrapper) break
currentContext = currentContext.baseContext
}
return null
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With