智能客服
你问我答,随时在线为你解决问题

























动态布局容器组件,支持在运行时动态切换不同的布局算法,不改变子组件的状态。使用DynamicLayout可以提升布局灵活性,简化界面适配和多视图切换的开发流程。适用于响应式布局(适配不同屏幕尺寸)、多视图模式切换(如列表/网格/瀑布流切换)、用户自定义布局等场景。
该组件从API version 24开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。
本模块接口仅可在Stage模型下使用。
可以包含子组件。
DynamicLayout(algorithm: LayoutAlgorithm)
动态布局容器。
卡片能力: 从API version 24开始,该接口支持在ArkTS卡片中使用。
元服务API: 从API version 24开始,该接口支持在元服务中使用。
模型约束: 此接口仅可在Stage模型下使用。
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| algorithm | LayoutAlgorithm | 是 | 指定动态布局容器的布局算法。支持使用RowLayoutAlgorithm(水平线性布局,适用于水平排列场景)、ColumnLayoutAlgorithm(垂直线性布局,适用于垂直排列场景)、StackLayoutAlgorithm(堆叠布局,适用于层叠覆盖场景)、GridLayoutAlgorithm(网格布局,适用于规整网格场景)和CustomLayoutAlgorithm(自定义布局,适用于复杂特殊布局场景)等布局算法实例,详见LayoutAlgorithm。取非法值(如null、undefined或无效的布局算法对象)时,按照StackLayoutAlgorithm布局子组件,子组件堆叠排列。 |
支持通用属性。
当布局算法为RowLayoutAlgorithm或ColumnLayoutAlgorithm时,子组件设置Flex布局属性生效,设置layoutGravity属性不生效。
当布局算法为StackLayoutAlgorithm时,子组件设置layoutGravity属性生效,设置Flex布局属性不生效。
当布局算法为CustomLayoutAlgorithm时,DynamicLayout组件FrameNode的setMeasuredSize方法优先级高于尺寸设置和边框属性,子组件FrameNode的measure和layout方法优先级高于ignoreLayoutSafeArea属性。
当布局算法为GridLayoutAlgorithm时,子组件设置Flex布局属性不生效,设置layoutGravity属性不生效,子组件通过GridLayoutAlgorithm参数控制位置。
该示例展示如何重写onMeasure、onLayout函数,实现瀑布流布局展示商品列表的功能。瀑布流布局通过测量阶段计算子组件高度并记录每列累计高度,在布局阶段将子组件分配到当前高度最小的列,实现自动填充效果。
从API version 24开始,新增onMeasure、onLayout。
- import { DynamicLayout, DynamicLayoutAttribute, CustomLayoutAlgorithm, LayoutAlgorithm, FrameNode, LayoutConstraint, Position } from '@kit.ArkUI';
-
- // 瀑布流布局算法
- class WaterfallLayout extends CustomLayoutAlgorithm {
- private columnCount: number = 2;
- private columnGap: number = 10;
- private rowGap: number = 10;
-
- onMeasure(self: FrameNode, constraint: LayoutConstraint): void {
- const childCount = self.getChildrenCount();
- const columnWidth = (constraint.maxSize.width - (this.columnCount - 1) * this.columnGap) / this.columnCount;
-
- // 记录每列的当前高度
- const columnHeights: number[] = new Array(this.columnCount).fill(0);
-
- for (let i = 0; i < childCount; i++) {
- const child = self.getChild(i);
- if (child) {
- // 通过将minSize和maxSize设置为相同值来约束子组件宽度
- const childConstraint: LayoutConstraint = {
- maxSize: {
- width: columnWidth,
- height: constraint.maxSize.height
- },
- minSize: {
- width: columnWidth,
- height: 0
- },
- percentReference: constraint.percentReference
- };
-
- child.measure(childConstraint);
-
- // 找到当前高度最小的列
- const minColumn = columnHeights.indexOf(Math.min(...columnHeights));
- columnHeights[minColumn] += child.getMeasuredSize().height + this.rowGap;
- }
- }
-
- const maxHeight = Math.max(...columnHeights);
- self.setMeasuredSize({
- width: constraint.maxSize.width,
- height: maxHeight
- });
- }
-
- onLayout(self: FrameNode, position: Position): void {
- const childCount = self.getChildrenCount();
- const measuredSize = self.getMeasuredSize();
- const columnWidth = (measuredSize.width - (this.columnCount - 1) * this.columnGap) / this.columnCount;
-
- // 记录每列的当前Y坐标
- const columnYs: number[] = new Array(this.columnCount).fill(0);
-
- for (let i = 0; i < childCount; i++) {
- const child = self.getChild(i);
- if (child) {
- const childSize = child.getMeasuredSize();
-
- // 找到当前Y坐标最小的列
- const minColumn = columnYs.indexOf(Math.min(...columnYs));
- const x = minColumn * (columnWidth + this.columnGap);
- const y = columnYs[minColumn];
-
- child.layout({ x, y });
-
- columnYs[minColumn] += childSize.height + this.rowGap;
- }
- }
-
- self.setLayoutPosition(position);
- }
- }
-
- @Entry
- @ComponentV2
- struct WaterfallLayoutExample {
- @Local algorithm: LayoutAlgorithm = new WaterfallLayout();
-
- // 商品数据
- private products: Product[] = [
- { id: '1', name: '时尚运动鞋', price: '¥399', height: 180, image: '商品图' },
- { id: '2', name: '休闲双肩包', price: '¥259', height: 220, image: '商品图' },
- { id: '3', name: '无线蓝牙耳机', price: '¥599', height: 150, image: '商品图' },
- { id: '4', name: '智能手表', price: '¥1299', height: 200, image: '商品图' },
- { id: '5', name: '太阳眼镜', price: '¥199', height: 130, image: '商品图' },
- { id: '6', name: '便携充电宝', price: '¥129', height: 170, image: '商品图' },
- { id: '7', name: '机械键盘', price: '¥459', height: 160, image: '商品图' },
- { id: '8', name: '游戏鼠标', price: '¥189', height: 140, image: '商品图' },
- { id: '9', name: '高清显示器', price: '¥1599', height: 210, image: '商品图' },
- { id: '10', name: '智能音箱', price: '¥299', height: 190, image: '商品图' }
- ];
-
- // 商品卡片组件
- @Builder ProductCard(product: Product) {
- Column() {
- Text(product.image)
- .fontSize(18)
- .margin({ bottom: 8 })
- Text(product.name)
- .fontSize(14)
- .fontWeight(FontWeight.Medium)
- .fontColor(0x333333)
- .margin({ bottom: 4 })
- .maxLines(1)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- Text(product.price)
- .fontSize(16)
- .fontColor(0xFF6B35)
- .fontWeight(FontWeight.Bold)
- }
- .width('100%')
- .padding(12)
- .backgroundColor(0xFAFAFA)
- .borderRadius(8)
- .border({ width: 1, color: 0xE0E0E0 })
- .height(product.height)
- .justifyContent(FlexAlign.Center)
- }
-
- build() {
- Column() {
- Text('商品列表 - 瀑布流布局')
- .fontSize(18)
- .fontWeight(FontWeight.Bold)
- .margin({ bottom: 20 })
-
- Scroll() {
- DynamicLayout(this.algorithm) {
- ForEach(this.products, (product: Product) => {
- this.ProductCard(product)
- })
- }
- .width('100%')
- .backgroundColor(0xEFEFEF)
- .borderRadius(12)
- .padding(10)
- }
- .scrollable(ScrollDirection.Vertical)
- .scrollBar(BarState.Auto)
- .edgeEffect(EdgeEffect.Spring)
- .width('100%')
- .layoutWeight(1)
-
- Text('商品卡片自动分配到高度最小的列')
- .fontSize(14)
- .fontColor(Color.Gray)
- .margin({ top: 12 })
- }
- .padding(20)
- .width('100%')
- .height('100%')
- }
- }
-
- // 商品数据模型
- interface Product {
- id: string;
- name: string;
- price: string;
- height: number;
- image: string;
- }

该示例通过改变@Local装饰的LayoutAlgorithm类型变量,实现动态切换DynamicLayout组件布局算法的功能。示例展示如何切换布局算法为RowLayoutAlgorithm(水平线性布局)、ColumnLayoutAlgorithm(垂直线性布局)、StackLayoutAlgorithm(堆叠布局)和GridLayoutAlgorithm(网格布局)。
示例中预置的layoutGravity属性仅在Stack布局算法下生效,在Row/Column布局算法下该属性不生效。
从API version 24开始,新增RowLayoutAlgorithm、ColumnLayoutAlgorithm、StackLayoutAlgorithm、GridLayoutAlgorithm。
- import { DynamicLayout, DynamicLayoutAttribute, RowLayoutAlgorithm, ColumnLayoutAlgorithm, StackLayoutAlgorithm, GridLayoutAlgorithm, LayoutAlgorithm, LengthMetrics } from '@kit.ArkUI';
-
- @Entry
- @ComponentV2
- struct LayoutSwitchExample {
- @Local algorithm: LayoutAlgorithm = new RowLayoutAlgorithm({
- space: LengthMetrics.vp(10),
- alignItems: VerticalAlign.Center
- });
- @Local childWidth: string = '20%'
- @Local childHeight: string = '20%'
-
- build() {
- Column() {
- // 使用状态变量控制布局算法
- DynamicLayout(this.algorithm) {
- Text('Item 1')
- .width(this.childWidth)
- .height(this.childHeight)
- .fontSize(14)
- .textAlign(TextAlign.Center)
- .backgroundColor(0xF5DEB3)
- .borderRadius(8)
- .layoutGravity(LocalizedAlignment.TOP_START)
- Text('Item 2')
- .width(this.childWidth)
- .height(this.childHeight)
- .fontSize(14)
- .textAlign(TextAlign.Center)
- .backgroundColor(0xF5DEB3)
- .borderRadius(8)
- .layoutGravity(LocalizedAlignment.TOP_END)
- Text('Item 3')
- .width(this.childWidth)
- .height(this.childHeight)
- .fontSize(14)
- .textAlign(TextAlign.Center)
- .backgroundColor(0xF5DEB3)
- .borderRadius(8)
- .layoutGravity(LocalizedAlignment.BOTTOM_START)
- Text('Item 4')
- .width(this.childWidth)
- .height(this.childHeight)
- .fontSize(14)
- .textAlign(TextAlign.Center)
- .backgroundColor(0xF5DEB3)
- .borderRadius(8)
- .layoutGravity(LocalizedAlignment.BOTTOM_END)
- }
- .width(300)
- .height(280)
- .backgroundColor(0xEFEFEF)
- .borderRadius(12)
- .padding(10)
-
- Column({ space: 10 }) {
- Row({ space: 10 }) {
- Button('Row布局')
- .fontSize(14)
- .onClick(() => {
- this.algorithm = new RowLayoutAlgorithm({
- space: LengthMetrics.vp(10),
- alignItems: VerticalAlign.Center
- });
- this.childWidth = '20%'
- this.childHeight = '20%'
- })
- Button('Column布局')
- .fontSize(14)
- .onClick(() => {
- this.algorithm = new ColumnLayoutAlgorithm({
- space: LengthMetrics.vp(10),
- alignItems: HorizontalAlign.Center
- });
- this.childWidth = '20%'
- this.childHeight = '20%'
- })
- }
- Row({ space: 10 }) {
- Button('Stack布局')
- .fontSize(14)
- .onClick(() => {
- this.algorithm = new StackLayoutAlgorithm({
- alignContent: LocalizedAlignment.CENTER
- });
- this.childWidth = '20%'
- this.childHeight = '20%'
- })
- Button('Grid布局')
- .fontSize(14)
- .onClick(() => {
- this.algorithm = new GridLayoutAlgorithm({
- columnsTemplate: '1fr 1fr',
- rowsGap: LengthMetrics.vp(5),
- columnsGap: LengthMetrics.vp(5)
- });
- this.childWidth = '100%'
- this.childHeight = '50%'
- })
- }
- }
- .margin({ top: 20 })
- }
- .padding(20)
- }
- }

该示例通过修改RowLayoutAlgorithm的space和justifyContent属性,实现DynamicLayout组件布局效果刷新的功能。
从API version 24开始,新增space、justifyContent属性。
- import { DynamicLayout, DynamicLayoutAttribute, RowLayoutAlgorithm, LengthMetrics } from '@kit.ArkUI';
-
- @Entry
- @ComponentV2
- struct PropertyChangeExample {
- algorithm: RowLayoutAlgorithm = new RowLayoutAlgorithm({
- space: LengthMetrics.vp(10),
- justifyContent: FlexAlign.Start
- });
-
- build() {
- Column() {
- DynamicLayout(this.algorithm) {
- Text('Item 1')
- .width(60)
- .height(40)
- .fontSize(14)
- .backgroundColor(0xF5DEB3)
- Text('Item 2')
- .width(60)
- .height(40)
- .fontSize(14)
- .backgroundColor(0xD2B48C)
- Text('Item 3')
- .width(60)
- .height(40)
- .fontSize(14)
- .backgroundColor(0xF5DEB3)
- }
- .width('100%')
- .height(80)
- .backgroundColor(0xEFEFEF)
-
- Row({ space: 10 }) {
- Button('增加间距')
- .fontSize(14)
- .onClick(() => {
- // 修改space属性触发重新布局
- const currentSpace = this.algorithm.space?.value;
- this.algorithm.space = LengthMetrics.vp(currentSpace as number + 5);
- })
- Button('居中对齐')
- .fontSize(14)
- .onClick(() => {
- // 修改justifyContent属性触发重新布局
- this.algorithm.justifyContent = FlexAlign.Center;
- })
- Button('两端对齐')
- .fontSize(14)
- .onClick(() => {
- // 修改justifyContent属性为两端对齐
- this.algorithm.justifyContent = FlexAlign.SpaceBetween;
- })
- }
- .margin({ top: 20 })
- }
- .padding(20)
- }
- }

智能客服
你问我答,随时在线为你解决问题
合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
解决方案
精准高效的一站式服务支持,助力开发者商业成功