Reputation: 1966
Per https://developer.android.com/jetpack/compose/interop/interop-apis , ComposeView and AbstractComposeView should facilitate interoperability between Compose and existing XML based apps.
I've had some success when deploying to a device, but XML previews that include Compose elements aren't working for me.
As a simplified example, consider:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="state"
type="ObservableState" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TestAtom
android:layout_width="match_parent"
android:layout_height="match_parent"
app:state="@{state}" />
</LinearLayout>
Making use of the following custom view file:
data class ObservableState(val text: ObservableField<String> = ObservableField("Uninitialized"))
data class State(val text: MutableState<String> = mutableStateOf(String()))
class TestAtom
@JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr) {
val state by mutableStateOf(State())
fun setState(observableState: ObservableState?) {
state.text.value = observableState?.text?.get() ?: "null"
}
@Composable
override fun Content() {
if (isInEditMode) {
val text = remember { mutableStateOf("Hello Edit Mode Preview!") }
TestAtomCompose(State(text = text))
} else {
TestAtomCompose(state)
}
}
}
@Composable
fun TestAtomCompose(state: State) {
Text(text = "Text: " + state.text.value, modifier = Modifier.wrapContentSize())
}
@Preview(name = "Test", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Composable
fun PreviewTestCompose() {
val text = remember { mutableStateOf("Hello World!") }
TestAtomCompose(State(text = text))
}
I have tried many variations and iterations on this, however none successfully allowed a Compose-based custom view to render in an XML layout preview. (the @Compose preview works as expected) The above example results in a preview render error: java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.LinearLayout.
1) Has anyone found a tactic to allow complex Compose-based custom views to render in XML preview panes?
2) Is there a way to transmit XML preview pane selection options, like theme and light/dark mode, to an embedded ComposeView to update its preview?
3) Is there a way to assign specific sample data from XML to a ComposeView to cause it to render differently in the preview? (similar to tools: functionality)
Upvotes: 12
Views: 3120
Reputation: 61
In order to preview in XML design a custom ComposableView that extend from AbstractComposeView you will need to tell to your view to use a custom recomposer.
AfzalivE from GitHub provide a gist about that: https://gist.github.com/AfzalivE/43dcef66d7ae234ea6afd62e6d0d2d37
Copy this file in your project, then override the onAttachToWindow method with the following:
override fun onAttachedToWindow() {
if (isInEditMode) {
setupEditMode()
}
super.onAttachedToWindow()
}
FYI: Google is working on a fix about this issue: https://issuetracker.google.com/u/1/issues/187339385?pli=1
Upvotes: 1