3、百分比与权重布局:使用百分比单位(%)和layoutWeight属性,实现父容器内的空间分配。
说到布局,很多新手会问:「我到底该用dp还是百分比?」
我的答案是——两者都要用,但用对地方。
百分比和权重,说白了就是让子组件「按比例分地盘」。你想想看,如果每个组件都写死宽度,换个屏幕就崩了。但用百分比或权重,父容器多大,子组件就跟着变。这才是自适应布局的精髓。
3.1 百分比单位(%):按父容器比例分配
鸿蒙的百分比单位,是相对于直接父容器的尺寸来计算的。
比如父容器宽度是300vp,你写width: "50%",那子组件就是150vp。父容器变到600vp,子组件自动变成300vp。嗯,就是这么简单。
核心要点:
- 百分比只对直接父容器生效,别指望它穿透到祖父级
- 支持 width、height、margin、padding 等属性
- 父容器必须有明确的尺寸,否则百分比会失效
我在项目中遇到过一个问题:给一个组件设了height: "50%",结果死活不生效。排查了半天才发现,它的父容器没设高度,用的是wrapContent。父容器自己都没高度,50%自然就无从谈起了。
来看个实际例子:
@Entry
@Component
struct PercentDemo {
build() {
Column() {
// 父容器占满屏幕宽度
Column() {
Text("我是50%宽度")
.width("50%")
.height(40)
.backgroundColor("#FFB6C1")
.textAlign(TextAlign.Center)
Text("我是80%宽度")
.width("80%")
.height(40)
.backgroundColor("#87CEEB")
.textAlign(TextAlign.Center)
Text("我是100%宽度")
.width("100%")
.height(40)
.backgroundColor("#98FB98")
.textAlign(TextAlign.Center)
}
.width("100%")
.height("auto")
.padding(10)
.backgroundColor("#F0F0F0")
}
.width("100%")
.height("100%")
}
}
这段代码的效果很直观:三个子组件分别占父容器的50%、80%、100%。父容器宽度是屏幕宽度,所以它们会跟着屏幕一起缩放。
我的小技巧:
百分比适合用在「相对比例固定」的场景。比如左侧菜单占30%,右侧内容占70%。这种比例关系不会因为屏幕变化而改变,用百分比最合适。
3.2 layoutWeight:更优雅的「按权重分地盘」
百分比有个缺点——你得自己算。比如三个组件要按1:2:3分配,用百分比你得算成16.67%、33.33%、50%。多麻烦啊。
这时候layoutWeight就派上用场了。你只需要告诉它「权重值」,系统自动帮你算比例。
layoutWeight 的规则:
- 所有设置了layoutWeight的组件,按权重值分配剩余空间
- 没设layoutWeight的组件,先占自己的固定尺寸,剩下的再分
- 权重值可以是整数或小数,比如1、2、3或者0.5、1.5
我记得有一次做平板适配,左侧导航栏固定80vp,右侧内容区要占满剩余空间。用百分比算半天都不对,换成layoutWeight一行代码搞定。
看代码:
@Entry
@Component
struct WeightDemo {
build() {
Row() {
// 左侧固定宽度
Column() {
Text("导航栏")
.width("100%")
.height("100%")
.backgroundColor("#FFD700")
.textAlign(TextAlign.Center)
}
.width(80) // 固定80vp
.height("100%")
// 右侧按权重分配
Column() {
Text("内容区 - 权重2")
.width("100%")
.height("100%")
.backgroundColor("#87CEEB")
.textAlign(TextAlign.Center)
}
.layoutWeight(2)
.height("100%")
Column() {
Text("侧边栏 - 权重1")
.width("100%")
.height("100%")
.backgroundColor("#98FB98")
.textAlign(TextAlign.Center)
}
.layoutWeight(1)
.height("100%")
}
.width("100%")
.height("100%")
}
}
这个例子中,左侧导航栏固定80vp,剩下的空间被右侧两个组件按2:1瓜分。内容区占2份,侧边栏占1份。屏幕越大,它们跟着变大,比例始终不变。
注意:
layoutWeight 只在 Row 或 Column 这种线性布局中生效。如果你用 Stack 或 Flex,它是不认的。我刚开始学的时候就在这上面栽过跟头,排查了半天才发现是布局容器用错了。
3.3 百分比 vs layoutWeight:怎么选?
说实话,这两个东西各有各的适用场景。我个人的习惯是这样的:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 比例固定,且所有子组件都按比例分 | layoutWeight | 不用算,代码更简洁 |
| 部分固定、部分按比例 | layoutWeight | 固定部分写死,剩余空间自动分配 |
| 单个组件的宽高比例 | 百分比 | 比如宽度占父容器60%,高度自适应 |
| 嵌套布局中的比例 | 百分比 | 权重只能管一层,百分比可以层层传递 |
| 需要精确控制边距 | 百分比 | margin和padding也支持百分比 |
你想想看,如果整个页面都是按比例分的,用layoutWeight多省事。但如果只是某个组件要占一半,用百分比更直接。
3.4 避坑指南:我踩过的那些坑
做自适应布局,坑是真的多。我挑几个典型的说说:
坑1:父容器没设尺寸,百分比失效
我曾经写了一个页面,给子组件设了width: "50%",结果怎么调都不对。后来发现父容器用的是wrapContent,它自己都没宽度,50%自然就是0了。记住:百分比依赖父容器的明确尺寸。
坑2:权重和固定尺寸混用,顺序很重要
在Row或Column中,先渲染固定尺寸的组件,再渲染有权重的组件。如果你把固定尺寸的组件写在后面,它可能会被挤到一边去。我建议:固定尺寸的组件放前面,有权重的放后面。
坑3:百分比和权重不能同时用在一个组件上
如果你给一个组件同时设了width: "50%"和layoutWeight(1),系统会优先用layoutWeight,百分比被忽略。别问我怎么知道的...嗯,调试了半天才发现。
3.5 实战:做一个自适应卡片布局
光说不练假把式。我们来做一个实际点的例子:一个卡片列表,每行显示3个卡片,卡片宽度按比例分配。
@Entry
@Component
struct CardLayout {
build() {
Column() {
// 第一行:3个卡片,按1:1:1分配
Row() {
CardItem("卡片A", "#FFB6C1")
.layoutWeight(1)
CardItem("卡片B", "#87CEEB")
.layoutWeight(1)
CardItem("卡片C", "#98FB98")
.layoutWeight(1)
}
.width("100%")
.height(120)
.padding(10)
// 第二行:中间卡片占2份,两边各1份
Row() {
CardItem("左", "#FFD700")
.layoutWeight(1)
CardItem("中(重点)", "#FF6347")
.layoutWeight(2)
CardItem("右", "#FFD700")
.layoutWeight(1)
}
.width("100%")
.height(120)
.padding(10)
}
.width("100%")
.height("100%")
.backgroundColor("#F5F5F5")
}
}
@Component
struct CardItem {
private title: string = ""
private bgColor: string = "#FFFFFF"
build() {
Column() {
Text(this.title)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
}
.width("100%")
.height("100%")
.backgroundColor(this.bgColor)
.borderRadius(8)
.margin(5)
.shadow({ radius: 4, color: "#33000000" })
}
}
这个例子中,第一行三个卡片平分宽度,第二行中间卡片占2份、两边各1份。不管屏幕多大,比例始终不变。这就是自适应布局的魅力——一次开发,多屏适配。
进阶技巧:
如果你想让卡片在横屏和竖屏下有不同的排列方式,可以结合媒体查询(MediaQuery)来动态调整权重值。比如竖屏时每行2个卡片(权重1:1),横屏时每行3个(权重1:1:1)。这个我们后面章节会详细讲。
好了,百分比和权重布局就讲到这里。说白了,这两个工具就是让你「按比例分地盘」的。记住:固定尺寸用dp,比例分配用百分比或权重。下节课我们聊聊更灵活的Flex布局,到时候你会发现,权重和Flex结合起来用,效果更炸裂。