HarmonyOS 6 ArkTS 自定义布局:判断子组件是否参与布局计算使用文档
文章目录核心价值核心原理判断子组件是否参与布局代码核心逻辑解析判断子组件是否参与布局1. 关键标记位2. 测量阶段判断是否参与尺寸计算onMeasureSize3. 布局阶段判断是否正常摆放onPlaceChildren核心API1. 子组件测量相关2. 子组件布局相关3. 布局约束常量总结核心价值精准控制子组件**测量measure与布局layout**生命周期空间不足时自动过滤子组件提升页面渲染效率完全自主决定子组件显示/隐藏不受默认布局规则限制核心原理判断子组件是否参与布局在自定义布局中子组件是否显示由两个阶段共同决定测量阶段onMeasureSize判断子组件是否计入容器尺寸、是否参与宽度/高度累加布局阶段onPlaceChildren判断子组件是正常摆放还是移至屏幕外隐藏两个阶段通过标记位overFlowIndex联动实现“超出即隐藏”的效果。代码// xxx.ets Entry Component struct Index { build() { Column() { CustomLayout({ builder: ColumnChildren }) } .justifyContent(FlexAlign.Center) .width(100%) .height(100%) } } Builder function ColumnChildren() { ForEach([1, 2, 3], (item: number, index: number) { // 目前不支持使用lazyForEach语法。 Text(S item) .fontSize(20) .width(60 10 * index) .height(100) .borderWidth(2) .margin({ left:10 }) .padding(10) }) } Component struct CustomLayout { // 只布局一行如果布局空间不够的子组件不显示的demo。 Builder doNothingBuilder() { }; BuilderParam builder: () void this.doNothingBuilder; result: SizeResult { width: 0, height: 0 }; overFlowIndex: number -1; onPlaceChildren(selfLayoutInfo: GeometryInfo, children: ArrayLayoutable, constraint: ConstraintSizeOptions) { let currentX 0; let infinity 100000; if (this.overFlowIndex -1) { this.overFlowIndex children.length; } for (let index 0; index children.length; index) { let child children[index]; if (index this.overFlowIndex) { // 如果子组件超出父组件范围将它布局到较偏的位置达到不显示的目的。 child.layout({x: infinity, y: 0}); continue; } child.layout({ x: currentX, y: 0 }) let margin child.getMargin(); currentX child.measureResult.width margin.start margin.end; } } onMeasureSize(selfLayoutInfo: GeometryInfo, children: ArrayMeasurable, constraint: ConstraintSizeOptions) { let width 0; let height 0; this.overFlowIndex -1; // 假定该组件的宽度不能超过200vp也不能超过最大约束。 let maxWidth Math.min(200, constraint.maxWidth as number); for (let index 0; index children.length; index) { let child children[index]; let childResult: MeasureResult child.measure({ minHeight: constraint.minHeight, minWidth: constraint.minWidth, maxWidth: constraint.maxWidth, maxHeight: constraint.maxHeight }) let margin child.getMargin(); let newWidth width childResult.width margin.start margin.end; if (newWidth maxWidth) { // 记录不该布局的组件的下标。 this.overFlowIndex index; break; } // 累积父组件的宽度和高度。 width newWidth; height Math.max(height, childResult.height margin.top margin.bottom); } this.result.width width; this.result.height height; return this.result; } build() { this.builder() } }运行效果如图核心逻辑解析判断子组件是否参与布局1. 关键标记位overFlowIndex: number -1;作用记录第一个溢出子组件的下标规则下标 ≥ overFlowIndex 的子组件 →不参与布局、直接隐藏下标 overFlowIndex 的子组件 →正常测量、正常摆放2. 测量阶段判断是否参与尺寸计算onMeasureSize核心目标计算总宽度判断子组件是否会超出容器若超出则标记截断位置。设置最大布局宽度maxWidth 200vp遍历子组件依次测量尺寸 外边距累加宽度如果超过限制记录当前下标为overFlowIndex终止遍历后续子组件不再参与尺寸计算最终容器尺寸 所有“允许显示”的子组件总宽度此阶段决定哪些子组件会占用容器空间。3. 布局阶段判断是否正常摆放onPlaceChildren核心目标根据测量阶段的标记正常摆放或隐藏子组件。遍历所有子组件如果子组件下标 ≥overFlowIndex溢出项使用child.layout({x: 100000, y: 0})将其移至屏幕外达到视觉隐藏效果如果子组件下标 overFlowIndex正常从左到右布局累加宽度 边距此阶段决定哪些子组件会在屏幕上可见。核心API1. 子组件测量相关API作用child.measure(constraint)执行子组件测量获取宽高结果child.getMargin()获取子组件外边距left/right/top/bottommeasureResult.width/height测量完成后子组件实际占用尺寸2. 子组件布局相关API作用child.layout({x, y})设置子组件最终显示坐标超大坐标隐藏x:100000移至屏幕外实现隐藏3. 布局约束常量let maxWidth Math.min(200, constraint.maxWidth as number);自定义布局最大宽度优先遵守自定义限制 父容器约束总结不支持 LazyForEach自定义布局内只能使用ForEach不能使用懒加载列表语法。隐藏≠销毁移至屏幕外的子组件仍存在节点树只是不可见。margin必须参与计算子组件外边距会占用布局空间计算总宽度时必须包含。测量与布局必须配对onMeasureSize与onPlaceChildren必须使用同一个标记位保证显示一致性。隐藏位置建议使用超大坐标如 100000隐藏避免使用 0/-9999 造成意外显示。如果这篇文章对你有帮助欢迎点赞、收藏、关注你的支持是持续创作的动力