项目已开源,开源地址: https://gitcode.com/nutpi/HarmonyosNextCaseStudyTutorial , 欢迎fork & star

效果演示

1. 引言

在现代UI设计中,按照特定比例分配空间的布局需求非常常见,例如黄金分割比例的内容区域、按照特定比例分配的多列布局等。HarmonyOS NEXT的RelativeContainer组件提供了链中节点权重(chainWeight)功能,能够按照指定的权重比例分配链中组件的空间,实现灵活的比例布局。本教程将详细讲解如何利用RelativeContainer的链中节点权重功能实现灵活的比例布局,帮助你掌握这一强大的布局技术。

2. 链中节点权重(ChainWeight)概述

链中节点权重是RelativeContainer链式布局的一个高级特性,它允许开发者为链中的每个组件分配权重值,系统会根据这些权重值按比例分配可用空间。权重值可以是任意正数,组件获得的空间比例等于其权重值除以所有组件权重值的总和。

2.1 链中节点权重的特性

  • 比例分配:根据权重比例分配空间
  • 灵活调整:通过调整权重值实现不同的分配比例
  • 链式样式兼容:可以与不同的链式样式(ChainStyle)结合使用
  • 动态调整:可以通过状态变量动态调整权重值

3. 案例分析:权重布局

3.1 完整代码

@Component
export struct WeightedLayout {
    build() {
        RelativeContainer() {
            // 左侧区域
            Column() {
                Text('左侧区域')
                    .fontSize(16)
                    .fontColor('#ffffff')
            }
            .width('100%')
            .height('100%')
            .backgroundColor('#007DFF')
            .justifyContent(FlexAlign.Center)
            .id("leftArea")
            .alignRules({
                left: { anchor: "parent", align: HorizontalAlign.Start },
                top: { anchor: "parent", align: VerticalAlign.Top },
                bottom: { anchor: "parent", align: VerticalAlign.Bottom }
            })

            // 中间区域
            Column() {
                Text('中间区域')
                    .fontSize(16)
                    .fontColor('#ffffff')
            }
            .width('100%')
            .height('100%')
            .backgroundColor('#FF7D00')
            .justifyContent(FlexAlign.Center)
            .id("middleArea")
            .alignRules({
                left: { anchor: "leftArea", align: HorizontalAlign.End },
                top: { anchor: "parent", align: VerticalAlign.Top },
                bottom: { anchor: "parent", align: VerticalAlign.Bottom }
            })

            // 右侧区域
            Column() {
                Text('右侧区域')
                    .fontSize(16)
                    .fontColor('#ffffff')
            }
            .width('100%')
            .height('100%')
            .backgroundColor('#7D00FF')
            .justifyContent(FlexAlign.Center)
            .id("rightArea")
            .alignRules({
                left: { anchor: "middleArea", align: HorizontalAlign.End },
                right: { anchor: "parent", align: HorizontalAlign.End },
                top: { anchor: "parent", align: VerticalAlign.Top },
                bottom: { anchor: "parent", align: VerticalAlign.Bottom }
            })
        }
        .chainMode([
            {
                id: "horizontalChain",
                direction: Direction.HORIZONTAL,
                style: ChainStyle.SPREAD,
                components: ["leftArea", "middleArea", "rightArea"],
                chainWeights: [1, 2, 1] // 1:2:1的比例
            }
        ])
        .width('100%')
        .height(200)
    }
}

3.2 代码详解

3.2.1 RelativeContainer容器设置

RelativeContainer() {
    // 子组件
}
.chainMode([
    {
        id: "horizontalChain",
        direction: Direction.HORIZONTAL,
        style: ChainStyle.SPREAD,
        components: ["leftArea", "middleArea", "rightArea"],
        chainWeights: [1, 2, 1] // 1:2:1的比例
    }
])
.width('100%')
.height(200)

这部分代码创建了一个RelativeContainer容器,并设置了以下属性:

属性说明
chainMode[...]定义链式布局数组
width'100%'容器宽度为父容器的100%
height200容器高度为200vp

这里的关键是chainMode属性,它定义了一个水平链:

  • id: "horizontalChain" - 链的唯一标识符
  • direction: Direction.HORIZONTAL - 链的方向为水平
  • style: ChainStyle.SPREAD - 链的样式为均匀分布
  • components: ["leftArea", "middleArea", "rightArea"] - 链中包含的组件ID数组
  • chainWeights: [1, 2, 1] - 链中组件的权重数组,按照1:2:1的比例分配空间

这个水平链将三个区域组件连接起来,并根据指定的权重比例分配空间,使中间区域的宽度是左右区域的两倍。

3.2.2 左侧区域设置

Column() {
    Text('左侧区域')
        .fontSize(16)
        .fontColor('#ffffff')
}
.width('100%')
.height('100%')
.backgroundColor('#007DFF')
.justifyContent(FlexAlign.Center)
.id("leftArea")
.alignRules({
    left: { anchor: "parent", align: HorizontalAlign.Start },
    top: { anchor: "parent", align: VerticalAlign.Top },
    bottom: { anchor: "parent", align: VerticalAlign.Bottom }
})

左侧区域的关键属性设置:

属性说明
width'100%'宽度为父容器的100%(实际宽度将由链中权重决定)
height'100%'高度为父容器的100%
backgroundColor'#007DFF'背景色为蓝色
justifyContentFlexAlign.Center内容居中对齐
id"leftArea"组件的唯一标识符,用于链式布局引用
alignRules{...}对齐规则

这里的关键点是为左侧区域设置了一个唯一的ID "leftArea",这样链式布局就可以引用它。同时,通过alignRules将其左侧对齐到父容器的左侧,顶部和底部分别对齐到父容器的顶部和底部,使其占据容器的整个高度。

3.2.3 中间区域设置

Column() {
    Text('中间区域')
        .fontSize(16)
        .fontColor('#ffffff')
}
.width('100%')
.height('100%')
.backgroundColor('#FF7D00')
.justifyContent(FlexAlign.Center)
.id("middleArea")
.alignRules({
    left: { anchor: "leftArea", align: HorizontalAlign.End },
    top: { anchor: "parent", align: VerticalAlign.Top },
    bottom: { anchor: "parent", align: VerticalAlign.Bottom }
})

中间区域的关键属性设置:

属性说明
width'100%'宽度为父容器的100%(实际宽度将由链中权重决定)
height'100%'高度为父容器的100%
backgroundColor'#FF7D00'背景色为橙色
justifyContentFlexAlign.Center内容居中对齐
id"middleArea"组件的唯一标识符,用于链式布局引用
alignRules{...}对齐规则

中间区域的左侧对齐到左侧区域的右侧,顶部和底部分别对齐到父容器的顶部和底部。

3.2.4 右侧区域设置

Column() {
    Text('右侧区域')
        .fontSize(16)
        .fontColor('#ffffff')
}
.width('100%')
.height('100%')
.backgroundColor('#7D00FF')
.justifyContent(FlexAlign.Center)
.id("rightArea")
.alignRules({
    left: { anchor: "middleArea", align: HorizontalAlign.End },
    right: { anchor: "parent", align: HorizontalAlign.End },
    top: { anchor: "parent", align: VerticalAlign.Top },
    bottom: { anchor: "parent", align: VerticalAlign.Bottom }
})

右侧区域的关键属性设置:

属性说明
width'100%'宽度为父容器的100%(实际宽度将由链中权重决定)
height'100%'高度为父容器的100%
backgroundColor'#7D00FF'背景色为紫色
justifyContentFlexAlign.Center内容居中对齐
id"rightArea"组件的唯一标识符,用于链式布局引用
alignRules{...}对齐规则

右侧区域的左侧对齐到中间区域的右侧,右侧对齐到父容器的右侧,顶部和底部分别对齐到父容器的顶部和底部。

4. 链中节点权重的高级应用

4.1 不同链式样式下的权重效果

链中节点权重在不同的链式样式下有不同的效果:

链式样式权重效果
ChainStyle.SPREAD按权重比例分配所有可用空间
ChainStyle.SPREAD_INSIDE按权重比例分配除首尾组件外的可用空间
ChainStyle.PACKED按权重比例分配组件之间的间距

4.2 黄金分割比例布局

可以使用黄金分割比例(约1:1.618)创建视觉上和谐的布局:

.chainMode([
    {
        id: "goldenRatioChain",
        direction: Direction.HORIZONTAL,
        style: ChainStyle.SPREAD,
        components: ["leftArea", "rightArea"],
        chainWeights: [1, 1.618] // 黄金分割比例
    }
])

4.3 垂直链中的权重分配

垂直链也支持权重分配:

.chainMode([
    {
        id: "verticalChain",
        direction: Direction.VERTICAL,
        style: ChainStyle.SPREAD,
        components: ["header", "content", "footer"],
        chainWeights: [1, 4, 1] // 1:4:1的比例
    }
])

4.4 动态权重

可以通过状态变量动态调整权重值,实现布局的动态变化:

@State leftWeight: number = 1;
@State middleWeight: number = 2;
@State rightWeight: number = 1;

// 在构建函数中
.chainMode([
    {
        id: "horizontalChain",
        direction: Direction.HORIZONTAL,
        style: ChainStyle.SPREAD,
        components: ["leftArea", "middleArea", "rightArea"],
        chainWeights: [this.leftWeight, this.middleWeight, this.rightWeight]
    }
])

// 在事件处理函数中
onExpandLeft() {
    this.leftWeight = 2;
    this.middleWeight = 1;
    this.rightWeight = 1;
}

5. 比例布局的最佳实践

5.1 常见的比例布局

以下是一些常见的比例布局及其实现方法:

布局类型实现方法
等分布局所有组件权重相等,如[1, 1, 1]
主次布局主要区域权重大,次要区域权重小,如[2, 1]
黄金分割按照黄金比例设置权重,如[1, 1.618]
自定义比例根据设计需求设置特定比例,如[3, 5, 2]

5.2 响应式比例布局

可以根据屏幕尺寸动态调整比例:

@State screenWidth: number = 0;

// 在aboutToAppear生命周期函数中获取屏幕宽度
aboutToAppear() {
    this.screenWidth = px2vp(window.getWindowWidth());
}

// 根据屏幕宽度计算权重
getWeights() {
    if (this.screenWidth < 600) {
        return [1, 1]; // 窄屏幕使用1:1比例
    } else {
        return [1, 2]; // 宽屏幕使用1:2比例
    }
}

6. 实际应用场景

链中节点权重分配在以下场景中特别有用:

  1. 多列布局:按照特定比例分配多列的宽度
  2. 分割视图:创建可调整比例的分割视图
  3. 内容布局:按照视觉重要性分配内容区域
  4. 响应式设计:根据屏幕尺寸动态调整布局比例

7. 总结

链中节点权重分配是RelativeContainer链式布局的一个强大特性,特别适合创建按照特定比例分配空间的布局。


全栈若城
1 声望2 粉丝