Skip to content

断点与多端适配

"一次开发,多端部署"是鸿蒙的核心目标。掌握断点系统、栅格布局和资源限定词是关键。


1. 多端适配的核心技术

一次开发,多端部署
├── 断点系统(Breakpoints)
├── 栅格布局(GridRow/GridCol)
├── 媒体查询(Media Queries)
├── 资源限定词(Resource Qualifiers)
└── 自适应布局(Flex/RelativeContainer)

2. 断点系统(Breakpoints)

2.1 什么是断点?

断点是一组屏幕宽度的阈值,在不同区间应用不同的布局策略。

断点屏幕宽度设备
xs< 320vp小屏手机
sm320-480vp大屏手机
md480-720vp折叠/平板
lg720-1280vp折叠展开/平板
xl1280-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 列和折叠屏适配。