搞定鸿蒙栅格布局:从基础到实战,让多设备适配变简单
鸿蒙多设备适配神器
如果你是鸿蒙应用开发者,肯定遇到过这样的头疼事:同一个界面,在手机上显示得好好的,放到平板上就乱七八糟,传到电视上更是没法看。别急,今天咱们就来聊聊能解决这个问题的 "神器"—— 栅格布局。虽然它有些老属性已经被淘汰了,但搞懂它不仅能帮你处理旧项目,还能让你更快上手新组件。话不多说,咱们开整!
一、栅格布局到底是个啥?为啥非要用它?
先给大家交个底,栅格布局就像咱们小时候玩的方格本,整个界面被分成了好多等宽的小格子,组件往格子里一放,不管屏幕多大,都能按比例乖乖待在该待的地方。这玩意儿最大的好处就是解决多设备适配问题—— 手机、平板、电视屏幕大小差那么多,有了栅格,就能让按钮、文字框这些组件在不同设备上 "自动站队",保证布局不乱套。
不过有几点重要的事儿得先说明白:
- 这功能从鸿蒙 API 7 就有了,但从 API 9 开始就不怎么维护了,官方更推荐用新的 GridCol 和 GridRow 组件(后面会讲为啥)。
- 用栅格布局有个硬性要求:必须得有个 GridContainer 容器当 "领导",所有用栅格属性的组件都得在它手下干活,不然属性就失效。
- 栅格的 "格子宽度" 和 "格子间距" 不是自己定的,得看最近的 GridContainer 爸爸怎么安排。
重点总结 1:栅格布局的核心作用和前提
- 作用:给不同尺寸设备(手机、平板、电视等)的布局定规矩,保证界面在各种设备上都整齐。
- 前提:必须有 GridContainer 容器组件当爹,所有栅格属性(gridSpan、gridOffset 等)都得在它的 "管辖范围" 内用。
- 现状:老属性从 API 9 或 14 开始逐步废弃,推荐用 GridCol、GridRow,但老项目维护还得懂。
二、扒一扒栅格布局的 "老伙计":那几个关键属性
虽然官方说这些属性要被淘汰了,但咱们搞开发的,老项目总免不了碰着。咱就把这几个 "老伙计" 一个个讲清楚,包括它们咋用、有啥坑。
1. useSizeType:让组件在不同设备上 "按需占格"
这个属性就像给组件发了 "不同场合的衣服",手机上穿 S 码,平板上穿 M 码,电视上穿 L 码。它能针对不同设备尺寸,单独设置组件占几格(span)和往旁边挪几格(offset)。
重点总结 2:useSizeType 的用法和参数
- 作用:给 xs、sm、md、lg 四种设备尺寸分别设置占格数和偏移量。
- 参数说明:
- xs:超小屏(比如手表)
- sm:小屏(比如手机)
- md:中屏(比如平板)
- lg:大屏(比如电视)
- 每个参数可以是数字(只设占格数),也可以是
{span: 数字, offset: 数字}(同时设占格和偏移)。
- 注意:API 9 开始废弃,推荐用新组件,但旧代码里常见。
代码示例:用 useSizeType 适配不同设备
@Entry
@Component
struct UseSizeTypeDemo {
build() {
Column() {
// 标题:说明这是useSizeType的示例
Text('用useSizeType适配不同设备').fontSize(18).margin(10)
// 栅格容器:所有栅格组件都得放在这里面
GridContainer() {
Row() { // 一行里面放三个子组件
// 左侧组件:在不同设备上占格不同
Row() {
Text('左侧区域').fontSize(20).color(Color.White)
}
.useSizeType({
xs: { span: 1, offset: 0 }, // 超小屏:占1格,不偏移
sm: { span: 1, offset: 0 }, // 手机:占1格,不偏移
md: { span: 1, offset: 0 }, // 平板:占1格,不偏移
lg: { span: 2, offset: 0 } // 电视:占2格,不偏移
})
.height(150)
.backgroundColor('#66bbb2cb') // 浅蓝色背景
// 中间组件:大屏占更多格子
Row() {
Text('中间区域').fontSize(20).color(Color.White)
}
.useSizeType({
xs: { span: 1, offset: 0 }, // 手表:占1格
sm: { span: 2, offset: 1 }, // 手机:占2格,往右挪1格
md: { span: 5, offset: 1 }, // 平板:占5格,往右挪1格
lg: { span: 7, offset: 2 } // 电视:占7格,往右挪2格
})
.height(150)
.backgroundColor('#66b6c5d1') // 浅青色背景
// 右侧组件:跟着设备尺寸调整位置
Row() {
Text('右侧区域').fontSize(20).color(Color.White)
}
.useSizeType({
xs: { span: 1, offset: 0 }, // 手表:占1格
sm: { span: 1, offset: 3 }, // 手机:占1格,往右挪3格
md: { span: 2, offset: 6 }, // 平板:占2格,往右挪6格
lg: { span: 3, offset: 9 } // 电视:占3格,往右挪9格
})
.height(150)
.backgroundColor('#66bbb2cb') // 浅蓝色背景
}
}
.backgroundColor('#f1f3f5') // 容器背景设为浅灰色
.margin(10) // 容器边缘留空隙
}
.width('100%') // 让整个布局占满屏幕宽度
}
}
代码解释:
这段代码里,我们在 GridContainer 里放了一行,行里有三个子组件(左侧、中间、右侧)。通过 useSizeType,给每个组件在不同设备尺寸下都定了 "规矩":
- 左侧组件在手机、平板上只占 1 格,到了电视上就占 2 格,这样在大屏上左侧不会太窄。
- 中间组件是重点内容,手机上占 2 格,平板上占 5 格,电视上占 7 格,保证主要内容在大屏上足够大。
- 偏移量(offset)的作用是让组件往右挪位置,比如手机上中间组件挪 1 格,就能避开左侧组件,避免重叠。
2. gridSpan:组件的 "默认占格数"
如果说 useSizeType 是 "特殊情况特殊处理",那 gridSpan 就是 "没特殊情况就按默认来"。当 useSizeType 没给某个设备尺寸设占格数时,就用 gridSpan 的值。
重点总结 3:gridSpan 的作用和注意事项
- 作用:设置组件的默认占格数,当 useSizeType 没覆盖某个尺寸时生效。
- 默认值:1(不设置的话,默认占 1 格)。
- 注意:API 14 开始废弃;设置后,组件宽度由栅格决定,自己设 width 可能没用。
代码示例:gridSpan 作为默认占格数
@Entry
@Component
struct GridSpanDemo {
build() {
Column() {
Text('gridSpan:默认占格数示例').fontSize(18).margin(10)
GridContainer() {
Row() {
// 组件A:只设gridSpan,没设useSizeType,所有设备都占2格
Row() {
Text('占2格').fontSize(20).color(Color.White)
}
.gridSpan(2) // 所有设备默认占2格
.height(100)
.backgroundColor('#ff7b7b') // 红色背景
// 组件B:useSizeType设了sm和lg,其他尺寸用gridSpan
Row() {
Text('sm占3格,其他占1格').fontSize(20).color(Color.White)
}
.gridSpan(1) // 默认占1格
.useSizeType({
sm: 3 // 手机上占3格,其他尺寸(xs、md、lg)没设,用默认1格
})
.height(100)
.backgroundColor('#7b9fff') // 蓝色背景
}
}
.backgroundColor('#f1f3f5')
.margin(10)
}
.width('100%')
}
}
代码解释:
- 组件 A 没设 useSizeType,只设了 gridSpan=2,所以不管在什么设备上,都固定占 2 格。
- 组件 B 设了 gridSpan=1(默认占 1 格),但 useSizeType 给 sm(手机)设了 3,所以:
- 手机上(sm):占 3 格(useSizeType 生效)。
- 手表(xs)、平板(md)、电视(lg):useSizeType 没设置,所以用 gridSpan=1,占 1 格。
3. gridOffset:组件的 "默认偏移量"
gridOffset 和 gridSpan 类似,是 "默认偏移量"。当 useSizeType 没给某个设备尺寸设偏移量时,就用 gridOffset 的值。偏移量的计算方式是:偏移距离 =(列宽 + 列间距)× 偏移列数。
重点总结 4:gridOffset 的作用和计算方式
- 作用:设置组件的默认偏移量,当 useSizeType 没覆盖某个尺寸时生效。
- 效果:组件往右挪(列宽 + 列间距)× offset 格的距离。
- 注意:API 14 开始废弃;偏移后,后面的组件会跟着挪位置(类似相对布局)。
代码示例:gridOffset 控制组件偏移
@Entry
@Component
struct GridOffsetDemo {
build() {
Column() {
Text('gridOffset:默认偏移量示例').fontSize(18).margin(10)
GridContainer() {
Row() {
// 左侧组件:不偏移,占2格
Row() {
Text('左侧(不偏移)').fontSize(16).color(Color.White)
}
.gridSpan(2)
.height(80)
.backgroundColor('#7bff7b') // 绿色背景
// 中间组件:默认偏移1格,sm尺寸偏移2格
Row() {
Text('中间(默认偏1格)').fontSize(16).color(Color.White)
}
.gridSpan(2)
.gridOffset(1) // 默认偏移1格
.useSizeType({
sm: { offset: 2 } // 手机上偏移2格
})
.height(80)
.backgroundColor('#ffbf7b') // 橙色背景
// 右侧组件:跟着中间组件偏移(相对布局效果)
Row() {
Text('右侧(自动跟随)').fontSize(16).color(Color.White)
}
.gridSpan(2)
.height(80)
.backgroundColor('#ff7b7b') // 红色背景
}
}
.backgroundColor('#f1f3f5')
.margin(10)
}
.width('100%')
}
}
代码解释:
- 左侧组件不设偏移(默认 offset=0),所以顶格靠左放,占 2 格。
- 中间组件设置了 gridOffset=1(默认偏移 1 格),所以在非手机设备上,会往右挪 1 格的距离(刚好避开左侧组件的 2 格,避免重叠)。
- 在手机(sm)上,中间组件偏移 2 格,这是因为手机屏幕窄,多挪一点能让布局更紧凑。
- 右侧组件没有设偏移,但因为中间组件挪了位置,它会自动跟在中间组件后面,这就是 "相对布局" 的效果 —— 后面的组件跟着前面的走。
3. 实战对比:useSizeType 和 gridSpan/gridOffset 效果一致
官方文档里有个很有意思的示例:用 useSizeType 设置的效果,和用 gridSpan+gridOffset 在特定尺寸下的效果能完全一样。这说明这两种方式本质上是相通的 —— 都是控制占格和偏移,只是 useSizeType 更灵活(能分尺寸设置)。
重点总结 4:两种方式的对比
- 相同点:都能控制组件占格和偏移,最终布局效果可以一致。
- 不同点:useSizeType 能分尺寸单独设置,gridSpan/gridOffset 是默认值,适合简单场景。
- 建议:复杂适配用 useSizeType(虽然废弃了),简单场景用 gridSpan/gridOffset,但更推荐新组件。
代码示例:两种方式效果对比
@Entry
@Component
struct CompareDemo {
build() {
Column() {
Text('两种方式效果对比').fontSize(18).margin(10)
// 第一行:用useSizeType设置sm尺寸
Text('方式1:useSizeType设置sm').fontSize(14).margin({ left: 10, top: 5 })
GridContainer() {
Row() {
Row() { Text('左').fontSize(20) }.useSizeType({ sm: { span: 1, offset: 0 } })
.height(100).backgroundColor('#66bbb2cb')
Row() { Text('中').fontSize(20) }.useSizeType({ sm: { span: 2, offset: 1 } })
.height(100).backgroundColor('#66b6c5d1')
Row() { Text('右').fontSize(20) }.useSizeType({ sm: { span: 1, offset: 3 } })
.height(100).backgroundColor('#66bbb2cb')
}
}
.backgroundColor('#f1f3f5').margin(10)
// 第二行:用gridSpan+gridOffset在sm尺寸下实现同样效果
Text('方式2:gridSpan+gridOffset(sm尺寸下效果相同)').fontSize(14).margin({ left: 10, top: 5 })
GridContainer() {
Row() {
Row() { Text('左').fontSize(20) }.gridSpan(1).gridOffset(0)
.height(100).backgroundColor('#66bbb2cb')
Row() { Text('中').fontSize(20) }.gridSpan(2).gridOffset(1)
.height(100).backgroundColor('#66b6c5d1')
Row() { Text('右').fontSize(20) }.gridSpan(1).gridOffset(3)
.height(100).backgroundColor('#66bbb2cb')
}
}
.backgroundColor('#f1f3f5').margin(10)
}
.width('100%')
}
}
代码解释:
- 方式 1 用 useSizeType 给 sm(手机)尺寸设了具体的 span 和 offset,让左、中、右三个组件分别占 1、2、1 格,偏移 0、1、3 格。
- 方式 2 没用 useSizeType,直接用 gridSpan(1、2、1)和 gridOffset(0、1、3),在手机上的效果和方式 1 完全一样。
- 这说明两种方式本质上都是在控制占格和偏移,只是 useSizeType 能针对不同尺寸 "定制化",更适合多设备适配。
三、栅格布局的 "坑" 和注意事项
虽然栅格布局很好用,但新手很容易踩坑。咱们整理了几个最常见的问题,帮你避坑。
1. 必须有 GridContainer 容器
所有用了 gridSpan、gridOffset、useSizeType 的组件,必须放在 GridContainer 里面,不然这些属性完全没用。就像孩子必须在教室里上课,跑到操场就不算数了。
错误示例:没有 GridContainer
@Entry
@Component
struct WrongDemo1 {
build() {
Column() {
// 错误:没有GridContainer,gridSpan无效
Row() {
Text('不会生效的gridSpan').gridSpan(2)
}
}
}
}
2. 废弃属性别再用新项目
官方明确说了,useSizeType 从 API 9 废弃,gridSpan 和 gridOffset 从 API 14 废弃,推荐用 GridCol 和 GridRow。就像旧手机虽然还能用,但新功能都只支持新手机,没必要在新项目里守着旧东西。
新组件 GridCol/GridRow 简单示例
@Entry
@Component
struct NewGridDemo {
build() {
Column() {
Text('新组件GridRow+GridCol示例').fontSize(18).margin(10)
// 新组件GridRow替代旧的Row+GridContainer
GridRow() {
// GridCol替代旧的gridSpan/useSizeType
GridCol({ span: { sm: 1, md: 2, lg: 3 } }) {
Text('新组件1').height(80).backgroundColor('#66bbb2cb').textAlign(TextAlign.Center)
}
GridCol({ span: { sm: 3, md: 4, lg: 5 } }) {
Text('新组件2').height(80).backgroundColor('#66b6c5d1').textAlign(TextAlign.Center)
}
}
.backgroundColor('#f1f3f5').margin(10)
}
}
}
3. 偏移量别设太大,避免超出屏幕
offset 是往右挪的格数,如果挪太多,组件可能跑到屏幕外面看不见。就像排队时往前站太多,就出了队伍范围了。
注意示例:偏移量合理设置
@Entry
@Component
struct OffsetWarningDemo {
build() {
Column() {
GridContainer() {
Row() {
// 注意:offset=10可能在小屏幕上超出范围(屏幕总格子可能不够10)
Row() { Text('可能超出屏幕').fontSize(16) }
.gridSpan(2)
.gridOffset(10) // 危险:偏移太大
.height(80)
.backgroundColor('#ff7b7b')
}
}
}
}
}
四、为啥栅格布局能搞定多设备适配?
咱们最后再聊聊底层逻辑:为啥栅格布局能让不同设备的布局保持一致?
其实原理很简单:不管屏幕多大,都把它分成固定数量的格子(比如手机分 4 格,平板分 8 格,电视分 12 格)。组件只需要说自己占几格,不用管具体宽度是多少。这样一来,手机上 1 格可能是 100px,平板上 1 格可能是 200px,但组件占 2 格的话,在手机上是 200px,平板上是 400px,比例始终一致,布局自然就不乱了。
就像搭积木,不管桌子多大,积木块的大小按桌子比例来,搭出来的造型就能保持原样,只是整体变大变小了而已。
总结:栅格布局学习要点
- 核心作用:解决多设备动态布局,保证不同屏幕上布局一致。
- 关键属性:
- useSizeType:分尺寸设占格和偏移(API 9 废弃)。
- gridSpan:默认占格数(API 14 废弃)。
- gridOffset:默认偏移量(API 14 废弃)。
- 前提条件:必须有 GridContainer 容器,否则属性无效。
- 未来方向:新项目用 GridCol 和 GridRow,旧项目维护才需要懂这些老属性。
掌握了这些,你再面对多设备适配时,就不会手忙脚乱了。虽然老属性要被淘汰,但理解它们的原理,能帮你更快上手新组件,让你的鸿蒙应用在任何设备上都能 "颜值在线"!
更多推荐



所有评论(0)