从 Row 到 WaterFlow:鸿蒙应用开发ArkUI布局全家桶教程
一、线性布局(Row / Column)
方向 | 语法糖 | 适用 |
---|---|---|
水平 | Row | 工具栏、按钮组 |
垂直 | Column | 表单、列表项 |
Column({ space: 8 }) {Text('用户名').fontSize(16)TextInput().placeholder('请输入')Button('登录')
}.width('100%').padding(16)
关键属性速记
justifyContent
→ 主轴对齐
alignItems
→ 交叉轴对齐
space
→ 相邻子组件间距
二、弹性布局(Flex)
一句话:Flex
= Row
+ Column
+ wrap
+ layoutWeight
Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {ForEach([1,2,3,4,5], () => {Text('标签').layoutWeight(1).margin(4)})
}
场景 | 推荐值 |
---|---|
等分 | layoutWeight(1) |
拉齐尾部 | justifyContent: FlexAlign.SpaceBetween |
换行 | wrap: FlexWrap.Wrap |
三、层叠布局(Stack)
Stack({ alignContent: Alignment.BottomEnd }) {Image($r('app.media.bg'))FloatingActionButton() // 悬浮按钮.margin(16)
}
zIndex 越大越靠上;支持 hitTestBehavior
控制事件穿透。
四、相对布局(RelativeContainer)
通过 9 个锚点(上/下/左/右/居中)精准定位:
RelativeContainer() {Text('A').id('A').alignRules({top: { anchor: '__container__', align: VerticalAlign.Top },left: { anchor: '__container__', align: HorizontalAlign.Start }})Text('B').id('B').alignRules({left: { anchor: 'A', align: HorizontalAlign.End },centerVertical: { anchor: 'A' }})
}
五、栅格布局(GridRow / GridCol)
12 栅格系统,断点自动切换:
GridRow({ gutter: 12 }) {ForEach(this.newsList, item =>GridCol({ span: { sm: 12, md: 6, lg: 4 } }) {NewsCard({ item })})
}
断点 | 典型宽度 | 列数 |
---|---|---|
sm | <520 vp | 12 |
md | 520-840 | 12 |
lg | >840 | 12 |
span
取值 1-12,必须 父容器设置columns: 12
(默认即 12)。
六、网格布局(Grid)
适用于 固定行列 的棋盘、相册、九宫格:
Grid() {ForEach(this.imgList, img =>GridItem() {Image(img).objectFit(ImageFit.Cover)})
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(8)
七、瀑布流布局(WaterFlow)
子项高度可变,自动填满空白;
WaterFlow() {LazyForEach(this.dataSource, item =>FlowItem() {ProductCard({ item })})
}
.columnsGap(12)
.rowsGap(12)
.columnsTemplate('1fr 1fr') // 两列
八、列表布局(List)
长列表首选,支持懒加载 + 滑动事件:
List({ lanes: { sm: 1, md: 2, lg: 3 } }) {LazyForEach(this.dataSource, item =>ListItem() {ArticleRow({ item })})
}
.onScrollIndex(start => console.log('开始索引:' + start))
九、轮播布局(Swiper)
Swiper() {ForEach(this.banners, banner =>Image(banner.url).borderRadius(12))
}
.autoPlay(true)
.interval(3000)
.indicator(true)
.displayCount({ sm: 1, md: 2, lg: 3 }) // 响应式
十、页签布局(Tabs)
底部、顶部、侧边一键切换:
Tabs({ barPosition: BarPosition.End }) {TabContent() { HomePage() }.tabBar('首页')TabContent() { ProfilePage() }.tabBar('我的')
}
.vertical(false) // true=侧边
.scrollable(true) // 支持手势滑动
十一、抽屉布局(SideBarContainer)
官方抽屉,零代码手势:
SideBarContainer(SideBarContainerType.Embed) {Column() { /* 抽屉内容 */ }.width(240)
}
.controlButton({top: 24,left: 24,icons: {shown: $r('app.media.menu'),hidden: $r('app.media.close')}
})
十二、导航布局(Navigation)
单/双/三分栏一站式导航,自动适配折叠屏:
Navigation() {NavRouter() {Text('一级')NavDestination() { DetailPage() }}
}
.mode(NavigationMode.Auto) // Auto=根据宽度自动分栏
十三、原子布局(DisplayPriority & PriorityLayout)
空间不足时按优先级隐藏:
Row() {Text('必须').displayPriority(2)Text('可隐藏').displayPriority(1)
}
优先级 越大 越先被隐藏;默认 0 表示不隐藏。
十四、响应式布局 2×2 简化断点
状态 | 阈值 | 目录名 |
---|---|---|
横向 Compact | <600 vp | hC |
横向 Regular | ≥600 vp | hR |
纵向 Compact | <800 vp | vC |
纵向 Regular | ≥800 vp | vR |
十五、常见错误 10 秒定位表
现象 | 根因 | 1 行解决 |
---|---|---|
栅格 span 无效 | 父容器未 columns:12 | GridRow({columns:12}) |
layoutWeight 无效 | 父容器无主轴尺寸 | 给 Row/Column 显式 width/height |
图片溢出 | 缺 objectFit | .objectFit(ImageFit.Cover) |
断点监听无回调 | 缺 responsiveWindow | module.json5 里开启 |
通知不显示 | 缺权限 | 动态申请 ohos.permission.NOTIFICATION |