当前位置: 首页 > article >正文

Compose 实践与探索十六 —— 与传统的 View 系统混用

Compose 发展初期的几年,会是新的模块用 Compose 写,然后逐渐的把老界面从 View 替换成 Compose 组件,直到全部或几乎全部是 Compose 代码的模式。

原生的 SurfaceView 与 TextureView 的重点是在它们底层的 Surface API,而不是 View 本身。Compose 并没有给出对等的实现,因此倘若你的项目中用到了它们,就仍需继续使用它们。这也是 View 到 Compose 的迁移到“几乎全部是 Compose 代码”的原因。

View 与 Compose 混用会有两个方向,在 View 系统中使用 Compose 代码、在 Compose 中使用 View 的代码。

1、在 View 中使用 Compose 代码

在 View 中使用 Compose 组件,需要将 Compose 组件放到 ComposeView 中,再将 ComposeView 当做一个 View 添加到整个 View 体系中:

class MigrationActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val composeView = ComposeView(this).apply {
            setContent { MigrationText() }
        }
        val linearLayout = LinearLayout(this).apply {
            addView(
                composeView,
                ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
            )
        }
        setContentView(linearLayout)
    }
}

@Composable
fun MigrationText() = Text("Compose")

关键步骤就是创建一个 ComposeView 对象,调用它的 setContent() 将 Compose 组件传进去。这是代码构建页面的方式,如果使用 XML 方式的话,将混合组件以 ComposeView 的方式声明在布局文件中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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/composeView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

然后在 Activity 中通过 findViewById() 拿到 ComposeView 后还是用 setContent() 设置 Compose 组件:

	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_migration)

        findViewById<ComposeView>(R.id.composeView).apply {
            setContent { MigrationText() }
        }
    }

2、在 Compose 中使用 View 代码

在项目逐渐由 View 迁移到 Compose 的过程中,势必会有 Compose 用到还未来得及迁移的用 View 实现的老组件。此时需要将 View 集成到 Compose 中,主要使用的是 AndroidView 组件:

/**
* 合成从 [factory] 获取的 Android View,工厂块将被调用一次,以获取要合成的视图,并且也保证在 UI 线程
* 上调用。因此,除了创建视图外,工厂还可以用于执行一次性初始化和设置视图常量属性。由于重新合成,更新块
* 可以多次运行(也在 UI 线程上),这是根据状态设置视图属性的正确位置。当状态发生变化时,该块将被重新执行
* 以设置新属性。请注意,该块在工厂块完成后也会立即运行一次。
*
* AndroidView 通常用于使用在 Compose 中无法重新实现且没有相应的 Compose API 的视图。目前的常见示例
* 包括 WebView、SurfaceView、AdView 等。
* AndroidView 不会将其内容剪切到布局边界。如果需要,可以使用 View.setClipToOutline 在子视图上剪切内容。
* 开发人员可能希望对 SurfaceView 的所有子类执行此操作,以保持其内容受限。
* 如果包含视图启用了嵌套滚动,AndroidView 具有嵌套滚动互操作能力。这意味着如果将此可组合项放置在参与
* 嵌套滚动的容器中,则此可组合项可以分派滚动增量。
* 参数:
* factory - 创建要合成视图的块。
* modifier - 要应用于布局的修改器。
* update - 在填充布局后要调用的回调函数。
*/
@Composable
@UiComposable
fun <T : View> AndroidView(
    factory: (Context) -> T,
    modifier: Modifier = Modifier,
    update: (T) -> Unit = NoOpUpdate
)

在 factory 内指定原生的布局结构,在 update 内做组件的数据更新:

	override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val context = LocalContext.current
            var name by remember { mutableStateOf("Compose") }
            Column {
                Text("Jetpack", Modifier.clickable { name += "1" })
                // factory 内指定 View 的布局,尾随 lambda 内进行数据更新动作
                AndroidView(factory = {
                    TextView(context).apply {
                        // 指定 TextView 文字的初始值
                        text = "初始值"
                    }
                }) {
                    // TextView 的文字与 name 关联,name 变化就会自动刷新 UI
                    it.text = name
                }
            }
        }
    }

效果如下:

请添加图片描述

原文地址:https://blog.csdn.net/tmacfrank/article/details/146431000
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/594946.html

相关文章:

  • Q2 电商订单数据分析优化
  • QT Quick(C++)跨平台应用程序项目实战教程 3 — 项目基本设置(窗体尺寸、中文标题、窗体图标、可执行程序图标)
  • uniapp整合SQLite(Android)
  • 集成学习(下):Stacking集成方法
  • MANISKILL3:GPU 并行机器人模拟和渲染,用于通用的具身AI
  • 贪心算法(10)(java)跳跃游戏
  • hive的基础函数>>集合函数, 条件函数, 类型转换函数
  • GEO:在AI时代抢占DeepSeekC位?
  • 深度学习项目--基于ResNet和DenseNet混合架构网络论文的复现(pytorch实现)
  • 【大模型理论篇】CogVLM:多模态预训练语言模型
  • python3.13.2安装详细步骤(附安装包)
  • 【设计模式】C++ 单例模式总结与最佳实践
  • OO_Unit1
  • .net core集成MQTT服务端
  • 【c++】异常处理
  • 硬件与软件的边界-从单片机到linux的问答详解
  • 糊涂人寄信——递推
  • Unity动画片段丢失(AnimationClip),如何进行重新绑定
  • DApp+公链/主链+钱包+Swap开发西安区块链公司
  • 华为中小型企业项目案例