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

Compose 自定义 - 布局 SubcomposeLayout

一、概念

当需要根据可用空间(约束)来动态加载子元素或布局,约束在 Layout() 中获取,但是所有子元素在布局阶段之前(也就是组合阶段)就完成了生成。这时就需要使用 SubcomposeLayout(),会将子元素的生成推迟到组合阶段再执行,让你在 measurePolicy() 中手动调用 subcompose() 来生成内容并返回 Measurables,更简单的方式是使用 BoxWithConstraints() 组件。

SubcomposeLayout()@Composable
fun SubcomposeLayout(
modifier: Modifier = Modifier,
measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult,
)
subcompose()

fun subcompose(slotId: Any?, content: @Composable () -> Unit): List<Measurable>

参数 slotId 唯一标识避免重复生成子元素。确保 slotId 的稳定性,否则每次都会重组影响性能。

参数 content 需要生成的子元素。

1.1 使用场景

独立上下文每一次 subcompose调用(针对不同的 slotId)都会创建一个独立的 CompositionContext。这比主 Composition 树稍重。
布局阶段的阻塞布局阶段通常是同步运行的,如果在 measure 块里做了极其繁重的组合逻辑,可能会导致掉帧(Jank)。
  • 动态加载子元素或布局:只有当你必须知道父容器尺寸才能决定生成什么子元素。

  • 跨子项依赖测量结果:先测量一个子元素才能决定下一个子元素是否生成,或需要在生成第二个子元素时使用第一个子元素的尺寸。

  • 基于可用尺寸的懒加载:包含 100 个条目的列表,仅加载可见的5个条目,并在滚动时再加载后续条目。

1.2 BoxWithContraints() 组件

源码底层就是通过 SubcomposeLayout 实现的,避免在 LazyList 的条目中使用,每个条目都会创建一个独立的 Subcomposition 上下文,它比普通的 Layout() 成本高得多,列表滚动时会产生大量的对象分配和上下文切换。

BoxWithConstraints()

@Composable
fun BoxWithConstraints(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable @UiComposable BoxWithConstraintsScope.() -> Unit,
)

作用域中共5个属性可以使用:constraints、maxHeight、maxWidth、minHeight、minWidth。

BoxWithConstraints { val maxHeight = constraints.maxHeight if (maxWidth > 600.dp) {...} }

二、使用举例

2.1 简易版 LazyRow

一个包含 1000 个数字的列表,横向排列,但只渲染屏幕内可见的数字。真实的 LazyColumn 逻辑要复杂得多(处理复用、回收、预加载、双向滚动等),但核心就是这个 while() 配合 subcompose()。

@Composable fun SimpleLazyRow( modifier: Modifier = Modifier, itemCount: Int, itemContent: @Composable (Int) -> Unit ) { SubcomposeLayout(modifier) { constraints -> var currentX = 0 //当前x坐标 var index = 0 val children = mutableListOf<Pair<Int, Placeable>>() //存储测量好的子元素 //循环:只要还没占满可用宽度就继续生成子元素,满了剩下的(屏幕外不可见的)条目不会被生成 while (currentX < constraints.maxWidth && index < itemCount) { //生成子元素并测量 //slotId 唯一标识确保重组时会复用之前的Composition上下文,只update而不是create val placeable = subcompose(index) { itemContent(index) }.map { measurable -> measurable.measure(constraints) }.first() //这里只有一个子元素 //存储子元素 children.add(currentX to placeable) //更新游标坐标 currentX += placeable.width index ++ } //只放置可见的条目 layout(currentX, constraints.maxHeight) { children.forEach { (x, placeable) -> placeable.placeRelative(x, 0) } } } }

2.2 展开折叠的 Text

文字默认折叠,点击后展开。 如果用普通的maxLines属性,可能很难拿到“展开按钮”应该放在哪里的精确坐标(尤其是文字最后一行没有填满时)。SubcomposeLayout 能先测一遍,效果不行就换另一种策略。

@Composable fun ExpandableText( modifier: Modifier = Modifier, text: String, isExpanded: Boolean ) { SubcomposeLayout(modifier) { constraints -> //先测量全部显示的子元素看看有多大 val placeable = subcompose(Unit) { Text(text) }.map { it.measure(constraints) }.first() //如果开启这贴并且子元素高度超过50.dp就折叠 if (!isExpanded && placeable.height > 50.dp) { //需要折叠逻辑: //1.限制文本重新生成子元素(通过约束或字符串) //2.生成按钮,subcompose(Unit) { Button(...) } //3.将按钮放在文本右下角 layout(...) {...} } else { //不需要折叠,直接摆放 layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
http://www.jsqmd.com/news/433338/

相关文章:

  • 解锁7大核心功能:G-Helper让华硕笔记本性能提升300%的终极指南
  • 基于Chord和LangChain的视频问答系统开发
  • Stable-Diffusion-v1-5-archive行业落地:工业零部件三维示意简图生成
  • 华硕游戏本色彩显示异常?三步修复让屏幕重现真实色彩
  • STM32MP157驱动ST7701S实现60FPS视频播放
  • GLM-OCR镜像深度使用:Node.js环境下的高性能并发调用实践
  • RePKG:让Wallpaper Engine资源处理效率提升5倍的技术方案
  • 灵感画廊入门指南:如何评估生成结果的艺术性而非仅技术指标
  • Ollama部署本地大模型|translategemma-12b-it开源翻译模型部署教程
  • 面向海外市场的AI内容生成:雯雯的后宫-造相Z-Image-瑜伽女孩英文提示词优化策略
  • OFA VQA镜像使用指南:修改LOCAL_IMAGE_PATH与VQA_QUESTION的完整步骤
  • 轻量级华硕硬件控制工具G-Helper:重新定义笔记本性能管理体验
  • STC增强型8051工程构建与LED闪烁实战
  • ESP32硬件架构与Web控制实战指南
  • 乙巳马年春联生成终端实战落地:乡村振兴直播间AI助农春联定制
  • GitHub界面中文化解决方案:提升开发效率的本地化配置指南
  • Nanbeige 4.1-3B Streamlit UI作品分享:15组高拟真二次元角色对话截图
  • STM32Fxxx中断EXTI重复触发问题解析与硬件级解决方案
  • League Akari革新性游戏辅助工具:重新定义英雄联盟玩家体验
  • Lychee模型与FastAPI集成:高性能多模态API开发
  • 综述不会写?专科生专属AI论文写作神器 —— 千笔·专业论文写作工具
  • 5秒克隆你的声音!用IndexTTS 2.0给短视频配音,保姆级安装配置避坑指南
  • Keil C51 8051 LED闪烁工程实战:从SFR映射到延时函数
  • Stable-Diffusion-v1-5-archive创意实验场:100种非主流风格提示词激发灵感
  • 4G显存也能玩转AI画图?手把手教你用Z-Image Nunchaku加速版出图(含RTX 50系显卡配置)
  • ESP32语音助手混合部署架构与本地服务器配置指南
  • AI重塑软件造价的游戏规则
  • Lua表的有序与无序本质:嵌入式脚本性能关键
  • LeagueAkari:重新定义英雄联盟游戏辅助体验
  • 乙巳马年春联生成终端惊艳效果:历史名联风格迁移(王羲之/颜真卿体)实验