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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值