Appearance
断点与多端适配
"一次开发,多端部署"是鸿蒙的核心目标。掌握断点系统、栅格布局和资源限定词是关键。
1. 多端适配的核心技术
一次开发,多端部署
├── 断点系统(Breakpoints)
├── 栅格布局(GridRow/GridCol)
├── 媒体查询(Media Queries)
├── 资源限定词(Resource Qualifiers)
└── 自适应布局(Flex/RelativeContainer)2. 断点系统(Breakpoints)
2.1 什么是断点?
断点是一组屏幕宽度的阈值,在不同区间应用不同的布局策略。
| 断点 | 屏幕宽度 | 设备 |
|---|---|---|
xs | < 320vp | 小屏手机 |
sm | 320-480vp | 大屏手机 |
md | 480-720vp | 折叠/平板 |
lg | 720-1280vp | 折叠展开/平板 |
xl | 1280-1920vp | 大屏平板 |
xxl | >= 1920vp | 折叠展开/大屏 |
2.2 使用断点
typescript
@Entry
@Component
struct Index {
private mediaQuery: MediaQueryContext = new MediaQueryContext()
private breakpoint: string = 'xs'
aboutToAppear() {
this.mediaQuery.on('change', (query: MediaQuery) => {
let width = query.mqls[0].mq.bounds.width
if (width >= 1280) {
this.breakpoint = 'xl'
} else if (width >= 720) {
this.breakpoint = 'lg'
} else if (width >= 480) {
this.breakpoint = 'md'
} else if (width >= 320) {
this.breakpoint = 'sm'
} else {
this.breakpoint = 'xs'
}
})
}
build() {
if (this.breakpoint === 'xl' || this.breakpoint === 'lg') {
// 大屏:横向布局
Row() {
Navigation()
.width('20%')
Content()
.width('80%')
}
} else {
// 小屏:纵向布局
Column() {
Navigation()
.width('100%')
Content()
.width('100%')
}
}
}
}3. 栅格布局(GridRow/GridCol)
3.1 基本概念
栅格系统将屏幕分为 12 列,通过 span 属性控制组件占据的列数。
屏幕 → | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
Row → | GridRow | 12列 |
Col → | GridCol | span: 3 → 占 3/12 = 1/4 |3.2 基本用法
typescript
GridRow() {
// 占 4/12 = 1/3
GridCol() {
Text('卡片1')
}
.span(4)
// 占 4/12 = 1/3
GridCol() {
Text('卡片2')
}
.span(4)
// 占 4/12 = 1/3
GridCol() {
Text('卡片3')
}
.span(4)
}
.gap(12)
.columnsTemplate('repeat(12, 1fr)')3.3 响应式栅格
typescript
GridRow() {
// 小屏占 12 列(全宽),大屏占 4 列
GridCol() {
Text('内容1')
}
.span({ default: 12, lg: 4 })
// 小屏占 12 列(全宽),大屏占 8 列
GridCol() {
Text('内容2')
}
.span({ default: 12, lg: 8 })
}
.gap(12)
.columnsTemplate('repeat(12, 1fr)')3.4 偏移与排序
typescript
GridRow() {
// 偏移 2 列
GridCol() {
Text('左对齐')
}
.span(4)
.offset(2) // 左边空 2 列
// 排序:排在最右边
GridCol() {
Text('靠右')
}
.span(4)
.order(99) // 最后渲染
}
.columnsTemplate('repeat(12, 1fr)')4. 媒体查询(Media Queries)
4.1 基本用法
typescript
@Entry
@Component
struct Index {
private mediaQuery: MediaQueryContext = new MediaQueryContext()
@State isLandscape: boolean = false
aboutToAppear() {
// 监听横屏/竖屏
this.mediaQuery.on('orientation', (orientation: MediaQuery) => {
this.isLandscape = orientation.mqls[0].mq.matches
})
}
build() {
if (this.isLandscape) {
// 横屏布局
Row() {
Content().width('60%')
Sidebar().width('40%')
}
} else {
// 竖屏布局
Column() {
Content().width('100%')
Sidebar().width('100%')
}
}
}
}4.2 媒体查询属性
| 查询条件 | 说明 |
|---|---|
orientation | 横屏/竖屏 |
displayMode | 单屏/分屏 |
windowSize | 窗口大小 |
resolution | 分辨率 |
prefersColorScheme | 浅色/深色模式 |
5. 资源限定词
5.1 目录结构
entry/src/main/resources/base/
├── element/
│ └── string.json
├── media/
│ ├── background.jpg
│ └── icon.png
├── profile/
│ └── main_page.json
└── rawfile/
└── config.json
entry/src/main/resources/ldpi/ # 低 DPI
entry/src/main/resources/mdpi/ # 中 DPI
entry/src/main/resources/hdpi/ # 高 DPI
entry/src/main/resources/xhdpi/ # 超高 DPI
entry/src/main/resources/zh-rCN/ # 中文
entry/src/main/resources/en-rUS/ # 英文
entry/src/main/resources/tablet/ # 平板
entry/src/main/resources/foldable/ # 折叠屏
entry/src/main/resources/dark/ # 深色模式
entry/src/main/resources/light/ # 浅色模式5.2 引用方式
typescript
// 资源限定词自动选择
// 在中文设备 → 读取 zh-rCN/string.json
// 在英文设备 → 读取 en-rUS/string.json
Text($r('app.string.hello')) // 自动根据语言选择
// 图片
Image($r('app.media.logo')) // 自动根据 DPI 选择
// 布局
@Entry({ src: 'pages/index' }) // 自动根据设备选择5.3 常用资源限定词
| 限定词 | 适用设备 |
|---|---|
base | 默认 |
phone | 手机 |
tablet | 平板 |
foldable | 折叠屏 |
tv | 电视 |
wearable | 穿戴设备 |
car | 车载 |
dark | 深色模式 |
light | 浅色模式 |
zh-rCN | 中文 |
en-rUS | 英文 |
6. 折叠屏适配
6.1 折叠状态检测
typescript
@Component
struct FoldableDemo {
@State foldAngle: number = 0
aboutToAppear() {
// 监听折叠角度变化
deviceManager.on('foldAngleChange', (angle: number) => {
this.foldAngle = angle
})
}
build() {
if (this.foldAngle >= 170) {
// 展开状态:单页宽布局
Text('展开状态:宽屏布局')
} else if (this.foldAngle <= 10) {
// 折叠状态:窄屏布局
Text('折叠状态:窄屏布局')
} else {
// 半折叠状态:分栏布局
Row() {
List('内容1')
Divider().vertical(true)
List('内容2')
}
}
}
}6.2 分栏(SplitPane)
typescript
SplitPane() {
Navigation()
.paneSize(200)
Content()
.paneSize(-1) // 自适应剩余空间
}
.mode(SplitPaneMode.Horizontal)
.gap(1)7. 适配方案决策树
你的应用需要适配哪些设备?
├─ 仅手机 → 标准布局即可
├─ 手机+平板 → 断点 + 栅格
├─ 折叠屏 → 折叠角度检测 + 分栏
├─ 多语言 → 资源限定词
├─ 深色模式 → dark/light 限定词
└─ 全设备 → 断点 + 栅格 + 媒体查询 + 限定词8. 面试高频考点
Q1: 多端适配的核心技术?
回答:断点系统(Breakpoints)、栅格布局(GridRow/GridCol)、媒体查询(Media Queries)、资源限定词(Resource Qualifiers)。
Q2: 栅格系统的列数?
回答:12 列。通过 span 属性控制组件占据的列数。
Q3: 折叠屏适配的关键?
回答:折叠角度检测、分栏(SplitPane)、断点切换、媒体查询。
🐱 小猫提示:多端适配记住 "断点 + 栅格(12列) + 媒体查询 + 资源限定词"。鸿蒙面试必考,尤其是栅格系统 12 列和折叠屏适配。