Compose - 与View互操作
一、概念
ComposeView负责对Android平台的Activity窗口的适配,AndroidComposeView负责连接LayoutNode视图系统与View视图系统。
二、View中使用Compose
<androidx.compose.ui.platform.ComposeView
android:id="@+id/composeView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
val composeView = findViewById<ComposeView>(R.id.composeView)
composeView.setContent { }
2.1 更改释放组合的策略 ViewCompositionStrategy
组合(Composition)是一种树状结构,通过组合项生成,用于描述 APP 的UI。当不再需要组合时,Compose 将不再跟踪其状态,并且组合会被释放以便释放资源。View组合策略(ViewCompositionStrategy)定义应该如何释放组合。
在单 Activity 纯 Compose 的 APP 中,通常只有一个组合处于活跃状态。第一次的重组发生于 Activity 被创建时(is created)。Activity通过调用 setContent( ) 来执行可组合项,并且组合保持活跃直到组合的内容与窗口分离——这种分离发生于 Activity 被销毁时,这是 ComposeView 默认的策略,如果你正在写一个纯 Compose 的 APP,这个策略就是你应该使用的。
View/Compose混合开发时,可能有多个组合,例如有一个通过Fragment进行分页的 ViewPager2,并且每个片段的内容都在 Compose中,则每个 ComposeView 都将是一个单独的组合。ViewPager2 中的每个 ComposeView 都维护一个单独的组合,每个组合与具有生命周期的组件(例如 Activity 或 Fragment)之间的交互是可能必须更改默认 ViewCompositionStrategy 以便在正确的时间释放的原因。
composeView.setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
2.1.1 DisposeOnDetachedFromWindow
当组合依赖的 ComposeView 从窗口分离时(View离开屏幕而且用户不可再见时)释放。(该默认策略在 1.2.0-beta02 版本已经被 DisposeOnDetachedFromWindowOrReleasedFromPool 所取代)
View与窗口分离发生在以下时候:
- 通过ViewGroup#removeView,将View从层次结构中移除。
- View是transition的一部分时。
- 当Activity被销毁时——onStop之后,但onDestroy之前。
使用场景:ComposeView是View层次结构中的唯一元素,或者是View/Compose的混合结构中的一员(不在Fragment中)。
2.1.2 DisposeOnDetachedFromWindowOrReleasedFromPool(默认)
当 ComposeView 在池容器中(例如RecyclerView)中使用时,View 元素会不断地附加和重新附加到窗口,因为元素会随着 UI 滚动而被回收。如果使用 DisposeOnDetachedFromWindow 组合也会不断地进行初始化和释放,频繁释放和重新创建组合会损害滚动性能,尤其是在快速浏览列表时。
改进后,同样在 ComposeView 与窗口分离时释放,而当它是池容器(如 RecyclerView)的一部分时,它将在池容器本身与窗口分离时或 Item 被丢弃时(即池已满)释放。
使用场景 :
- ComposeView是View层次结构中的唯一元素,或者是View/Compose的混合结构中的一员(不在Fragment中)。
- ComposeView是池容器里面的一个item,例如RecyclerView。
2.1.3 DisposeOnLifecycleDestroyed
当 ComposeView 与已知的 LifecycleOwner 是一对一的情况下使用,例如一个 Fragment 的 View,当该 View 从窗口中分离(也就是说 Fragment 在屏幕上不再可见),并且 Fragment 可能还没有被销毁(onDestory未被调用),这种情况会发生在滑动 ViewPager2 的 Fragment 时,如果使用上述的任何一种策略,组合将被过早的释放,从而导致潜在的状态丢失(例如,丢失LazyColumn中的滚动状态)。
当 ComposeView 对应的 Lifecycle 被销毁时释放,必须提供 Lifecycle 或者 LifecycleOwner。
使用场景:作为Fragment中的View的ComposeView。(ComposeView 作为 RecyclerView 中的一个item,同时RecyclerView位于 Fragment,该使用哪个?用ComposeView 的直接父元素定应用哪种策略——因此,由于ComposeView是RecyclerView中的一个item,你将使用DisposeOnDetachedFromWindowOrReleasedFromPool,否则使用DisposeOnLifecycleDestroyed。)
2.1.4 DisposeOnViewTreeLifecycleDestroyed
当ViewTreeLifecycleOwner提供的Lifecycle被销毁时,组合将被释放(viewTree提供的Lifecycle和组件提供的Lifecycle生命周期不一致,例如Fragment#mView和Fragment提供的Lifecycle不一样)。(如果 Lifecycle 对象已知使用 DisposeOnLifecycleDestroyed,否则使用DisposeOnViewTreeLifecycleDestroyed)。
- 作为Fragment中的View的ComposeView。
- 生命周期未知的View中的ComposeView。
三、Compose中使用View
3.1 单个控件
fun <T : View> AndroidView( factory: (Context) -> T, //接收一个Context参数, 用来构建一个View modifier: Modifier = Modifier, onReset: ((T) -> Unit)? = null, onRelease: (T) -> Unit = NoOpUpdate, update: (T) -> Unit = NoOpUpdate //参数 T 就是在 favtory 中构建的 View,用来读取 state 并设置到 View 中。 ) |
@Composable
fun SwipeableSample(str: String) {
val content = remember(str){ Html.fromHtml(str, 1) }
AndroidView(
factory = { context ->
TextView(context).apply {
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
movementMethod = LinkMovementMethod.getInstance() //超链接可点击
}
},
update = {textView ->
textView.text = content
}
)
}
3.2 布局文件
3.2.1 开启 ViewBingding
android {
viewBinding {
enabled = true
}
}
3.2.2 添加依赖
记得 build 一下。
implementation 'androidx.compose.ui:ui-viewbinding'
3.2.3 使用 AndroidViewBinding
fun <T : ViewBinding> AndroidViewBinding( factory: (inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean) -> T, modifier: Modifier = Modifier, onReset: (T.() -> Unit)? = null, onRelease: T.() -> Unit = { }, update: T.() -> Unit = { } ) |
@Composable
private fun Demo() {
//DemoLayoutBinding 为 ViewBind 生成的类
AndroidViewBinding(DemoLayoutBinding::inflate) {
sampleButton.setBackgroundColor(Color.GRAY)
}
}
更多推荐
所有评论(0)