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

server/2025/3/22 18:03:39/

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 体系中:

kotlin">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)}
}uiltin">@Composable
fun MigrationText() = Text("Compose")

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

kotlin"><?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.ComposeViewandroid:id="@+id/composeView"android:layout_width="wrap_content"android:layout_height="wrap_content" />
</LinearLayout>

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

kotlin">	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 组件:

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

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

kotlin">	override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val context = LocalContext.currentvar 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 变化就会自动刷新 UIit.text = name}}}}

效果如下:

请添加图片描述


http://www.ppmy.cn/server/177108.html

相关文章

浅谈跨平台框架的演变(H5混合开发->RN->Flutter)

引言 这里分为四个阶段&#xff1a; 第一阶段 &#xff1a; 原生开发 第二阶段 &#xff1a; H5混合开发 第三阶段&#xff1a; 跨平台RN 第四阶段&#xff1a; 跨平台Flutter 正文 第一阶段&#xff1a; 原生开发 开发成本比较大 &#xff1a; 需要Android 和ios 开发两…

django设置admin的排列顺序,耗3小时【躲坑指南】

django 项目中&#xff0c;这个数据栏目的显示排列顺序我希望更贴近业务 比如要让【商品货品信息】中的9个数据表根据人为规定来进行排序 结果&#xff1a;工程量很大。 能够实现人为的自定义排序 最简单的设置就是给模型添加号数标记 主应用中创建admin–设置了其中一个应用…

Pytorch中的torch.utils.data.Dataset 类

1、使用方法 from torch.utils.data import Dataset 2、torch.utils.data.Dataset 类的定义 class Dataset(Generic[_T_co]):r"""An abstract class representing a :class:Dataset.All datasets that represent a map from keys to data samples should sub…

油候插件、idea、VsCode插件推荐(自用)

开发软件&#xff1a; 之前的文章&#xff1a; 开发必装最实用工具软件与网站 推荐一下我使用的开发工具 目前在用的 油候插件 AC-baidu-重定向优化百度搜狗谷歌必应搜索_favicon_双列 让查询变成多列&#xff0c;而且可以流式翻页 Github 增强 - 高速下载 github下载 TimerHo…

基于ArcGIS和ETOPO-2022 DEM数据分层绘制全球海陆分布

第〇部分 前言 一幅带有地理空间参考、且包含海陆分布的DEM图像在研究区的绘制中非常常见&#xff0c;本文将实现以下图像的绘制 关键步骤&#xff1a; &#xff08;1&#xff09;NOAA-NCEI官方下载最新的ETOPO-2022 DEM数据 &#xff08;2&#xff09;在ArcGIS&#xff08;…

JavaIO流的使用和修饰器模式(直击心灵版)

系列文章目录 JavaIO流的使用和修饰器模式 文章目录 系列文章目录前言一、字节流&#xff1a; 1.FileInputStream(读取文件)2.FileOutputStream(写入文件) 二、字符流&#xff1a; 1..基础字符流:2.处理流&#xff1a;3.对象处理流&#xff1a;4.转换流&#xff1a; 三、修饰器…

【一起学Rust | Tauri2.0框架】基于 Rust 与 Tauri 2.0 框架实现全局状态管理

前言 在现代应用程序开发中&#xff0c;状态管理是构建复杂且可维护应用的关键。随着应用程序规模的增长&#xff0c;组件之间共享和同步状态变得越来越具有挑战性。如果处理不当&#xff0c;状态管理可能会导致代码混乱、难以调试&#xff0c;并最终影响应用程序的性能和可扩…

Lineageos 22.1(Android 15)实现负一屏

一、前言 方案是参考的这位大佬的&#xff0c;大家可以去付费订阅支持一波。我大概理一下Android15的修改。 大佬的方案代码 二、Android15适配调整 1.bp调整&#xff0c;加入aidl引入&#xff0c;这样make之后就可以索引代码了 filegroup {name: "launcher-src"…