Jetpack Compose 与 XML 预览的互操作性

Dav*_*ave 12 android android-layout android-jetpack-compose

根据https://developer.android.com/jetpack/compose/interop/interop-apis,ComposeView 和 AbstractComposeView 应该促进 Compose 和现有基于 XML 的应用程序之间的互操作性。

我在部署到设备时取得了一些成功,但包含 Compose 元素的 XML 预览对我不起作用。
作为一个简化的示例,请考虑:

<?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>
Run Code Online (Sandbox Code Playgroud)

使用以下自定义视图文件:

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))
}
Run Code Online (Sandbox Code Playgroud)

我对此尝试了许多变体和迭代,但是没有一个成功地允许基于 Compose 的自定义视图在 XML 布局预览中呈现。(@Compose 预览按预期工作)上面的示例会导致预览渲染错误:java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.LinearLayout

1) 有没有人找到一种策略来允许复杂的基于 Compose 的自定义视图在 XML 预览窗格中呈现?

2) 有没有办法将 XML 预览窗格选择选项(例如主题和亮/暗模式)传输到嵌入式 ComposeView 以更新其预览?

3) 有没有办法将 XML 中的特定示例数据分配给 ComposeView,以使其在预览中呈现不同的效果?(类似于工具:功能)

小智 1

为了在 XML 设计中预览从 AbstractComposeView 扩展的自定义 ComposableView,您需要告诉您的视图使用自定义重构器。

GitHub 上的 AfzalivE 提供了相关要点: https://gist.github.com/AfzalivE/43dcef66d7ae234ea6afd62e6d0d2d37

将此文件复制到您的项目中,然后使用以下内容重写 onAttachToWindow 方法:

override fun onAttachedToWindow() {
    if (isInEditMode) {
        setupEditMode()
    }
    super.onAttachedToWindow()
}
Run Code Online (Sandbox Code Playgroud)

仅供参考: Google 正在修复此问题: https://issuetracker.google.com/u/1/issues/187339385 ?pli=1