99天梭哈HarmonyOS到入职成功-第2天-一次开发多端部署方案(栅格布局GridRow/GridCol和相对布局RelativeContainer)
99天梭哈HarmonyOS到入职成功-第2天-一次开发多端部署方案(栅格布局GridRow/GridCol和相对布局RelativeContainer)
大家好!我是黑臂麒麟(起名原因:一个出生全右臂自带纹身的高质量程序员😏),也是一位6+(约2个半坤年)的前端;
学习如像练武功一样,理论和实践要相结合,学一门只是也是一样;
这里会用两周的时间把所学的常用ArkUI基础的常用组件输出在网;
如需深究可前往高级ArkTS系列课程;
望对学习鸿蒙小伙伴有所帮助;
文章目录
前言:
本篇介绍响应式布布局中第二篇,响应式布局第一遍媒体查询(mediaquery),这篇包含两个模块知识点:
- 栅格布局(GridRow/GridCol)
- 相对布局(RelativeContainer)
这篇重点放在网格布局(GridRow/GridCol)。在响应式布局中,比较常用不同屏幕(手机,平板,车机平板)的兼容,一次开发多端部署方案中,它是不可缺少,必须掌握。 相对布局(RelativeContainer)作为小伙伴知识储备。
栅格布局(GridRow/GridCol)
如果是前端小伙伴看到栅格布局很容想到Bootstrp。对!鸿蒙的栅格布局和bootstrp在有些相似。所以前端小伙伴就容易理解,应用开发小伙伴不用担心,我会用通俗易懂语言去解释。
子组件
可以包含GridCol子组件。
接口
GridRow(option?: {columns?: number | GridRowColumnOption, gutter?: Length | GutterOption, breakpoints?: BreakPoints, direction?: GridRowDirection})
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| gutter | Length | GutterOption | 否 | 栅格布局间距,x代表水平方向 |
| columns | number | GridRowColumnOption | 否 | 设置布局列数 |
breakpoints |
BreakPoints | 否 | 设置断点值的断点数列以及基于窗口或容器尺寸的相应参照 |
| direction | GridRowDirection | 否 | 栅格布局排列方向 |
GutterOption
| 参数名 | 参数类型 | 必填 | 参数描述 |
|---|---|---|---|
| x | Length | GridRowSizeOption | 否 | 水平gutter option |
| y | Length | GridRowSizeOption | 否 | 竖直gutter option |
网格系统断点
栅格系统以设备的水平宽度(屏幕密度像素值,单位vp)作为断点依据,定义设备的宽度类型,形成了一套断点规则。开发者可根据需求在不同的断点区间实现不同的页面布局效果。
这里通俗一点的意思讲:就是我们利用breakpoints属性设置vp值,自己个来设置断点。
默认断点将设备宽度分为xs、sm、md、lg四类:
| 参数名 | 取值范围(vp) | 设备描述 |
|---|---|---|
| xs | [0, 320) | 最小宽度类型设备 |
| sm | [320, 520) | 小宽度类型设备 |
| md | [520, 840) | 中等宽度类型设备 |
| lg | [840, +∞) | 大宽度类型设备 |
但我们可以使用breakpoints自定义修改断点的取值范围, 除上面四个断电外,有增加了两个xl,xxl。整理下表容易查看:
| 参数名 | 设备描述 |
|---|---|
| xs | 最小宽度类型设备 |
| sm | 小宽度类型设备 |
| md | 中等宽度类型设备 |
| lg | 大宽度类型设备 |
| xl | 特大宽度类型设备 |
| xxl | 超大宽度类型设备 |
- 针对断点位置,开发者根据实际使用场景,通过一个单调递增数组设置。由于breakpoints最多支持六个断点,单调递增数组长度最大为5
breakpoints: {value: ['100vp', '200vp']}
表示启用xs、sm、md共3个断点,小于100vp为xs,100vp-200vp为sm,大于200vp为md。
breakpoints: {value: ['320vp', '520vp', '840vp', '1080vp']}
表示启用xs、sm、md、lg、xl共5个断点,小于320vp为xs,320vp-520vp为sm,520vp-840vp为md,840vp-1080vp为lg,大于1080vp为xl。
- 栅格系统通过监听窗口或容器的尺寸变化进行断点,通过reference设置断点切换参考物。 考虑到应用可能以非全屏窗口的形式显示,以应用窗口宽度为参照物更为通用。
案例
上面我们提到了断点可以使用breakpoints来自定义,我们通过案例去理解这个属性;
网格默认列数是12等分列数,通过配置breakpoints将其分成六个区间,在各区间中,每个栅格子元素占用的列数均不同。
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
...
GridRow({
breakpoints: {
value: ['200vp', '300vp', '400vp', '500vp', '600vp'],
reference: BreakpointsReference.WindowSize
}
}) {
ForEach(this.bgColors, (color, index) => {
GridCol({
span: {
xs: 2, // 在最小宽度类型设备上,栅格子组件占据的栅格容器2列。
sm: 3, // 在小宽度类型设备上,栅格子组件占据的栅格容器3列。
md: 4, // 在中等宽度类型设备上,栅格子组件占据的栅格容器4列。
lg: 6, // 在大宽度类型设备上,栅格子组件占据的栅格容器6列。
xl: 8, // 在特大宽度类型设备上,栅格子组件占据的栅格容器8列。
xxl: 12 // 在超大宽度类型设备上,栅格子组件占据的栅格容器12列。
}
}) {
Row() {
Text(`${index}`)
}.width("100%").height('50vp')
}.backgroundColor(color)
})
}

布局的总列数
GridRow中通过columns设置栅格布局的总列数。
- 上面提到默认网格默认列数是12等分列数,是在columns未设置的情况下,任何单点下,都是12等分。
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown,Color.Red, Color.Orange, Color.Yellow, Color.Green];
...
GridRow() {
ForEach(this.bgColors, (item, index) => {
GridCol() {
Row() {
Text(`${index + 1}`)
}.width('100%').height('50')
}.backgroundColor(item)
})
}

- 也可以自己使用columns为自定义值,效果如下:
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
@State currentBp: string = 'unknown';
Row() {
GridRow({ columns: 4 }) {
ForEach(this.bgColors, (item, index) => {
GridCol() {
Row() {
Text(`${index + 1}`)
}.width('100%').height('50')
}.backgroundColor(item)
})
}
.width('100%').height('100%')
.onBreakpointChange((breakpoint) => {
this.currentBp = breakpoint
})
}
.height(160)
.border({ color: Color.Blue, width: 2 })
.width('90%')
Row() {
GridRow({ columns: 8 }) {
ForEach(this.bgColors, (item, index) => {
GridCol() {
Row() {
Text(`${index + 1}`)
}.width('100%').height('50')
}.backgroundColor(item)
})
}
.width('100%').height('100%')
.onBreakpointChange((breakpoint) => {
this.currentBp = breakpoint
})
}
.height(160)
.border({ color: Color.Blue, width: 2 })
.width('90%')

column还可以在自定义点断点时,设置不同的列数等分:
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown]
GridRow({ columns: { sm: 4, md: 8 }, breakpoints: { value: ['200vp', '300vp', '400vp', '500vp', '600vp'] } }) {
ForEach(this.bgColors, (item, index) => {
GridCol() {
Row() {
Text(`${index + 1}`)
}.width('100%').height('50')
}.backgroundColor(item)
})
}

排列方向和间距
排列方向控制可以利用direction定义,可设置为GridRowDirection.Row(从左往右排列)或GridRowDirection.RowReverse(从右往左排列),效果分别是:
- 子组件默认从左往右排列
GridRow({ direction: GridRowDirection.Row }){}

- 子组件从右往左排列
GridRow({ direction: GridRowDirection.RowReverse }){}

gutter属性设置子元素在水平和垂直方向的间距
GridRow({ gutter: { x: 20, y: 50 } }){}

可以看到列间距是20,行间距是50;
子组件GridCol
GridCol是GridRow组件的子组件,它拥有三个属性分别是span(占用列数),offset(偏移列数),order(元素序号),设置属性有两种方式:
- 传参方式
- 属性方式
GridCol({ span: 2 }){}
GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 } }){}
GridCol({ offset: 2 }){}
GridCol({ offset: { xs: 2, sm: 2, md: 2, lg: 2 } }){}
GridCol({ order: 2 }){}
GridCol({ order: { xs: 1, sm: 2, md: 3, lg: 4 } }){}
GridCol(){}.span(2)
GridCol(){}.span({ xs: 1, sm: 2, md: 3, lg: 4 })
GridCol(){}.offset(2)
GridCol(){}.offset({ xs: 1, sm: 2, md: 3, lg: 4 })
GridCol(){}.order(2)
GridCol(){}.order({ xs: 1, sm: 2, md: 3, lg: 4 })
span
子组件占栅格布局的列数,决定了子组件的宽度,默认为1。
- 当类型为
number时,子组件在所有尺寸设备下占用的列数相同
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
...
GridRow({ columns: 8 }) {
ForEach(this.bgColors, (color, index) => {
GridCol({ span: 2 }) {
Row() {
Text(`${index}`)
}.width('100%').height('50vp')
}
.backgroundColor(color)
})
}

- 也可以在六种不同尺寸(xs, sm, md, lg, xl, xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
...
GridRow({ columns: 8 }) {
ForEach(this.bgColors, (color, index) => {
GridCol({ span: { xs: 1, sm: 2, md: 3, lg: 4 } }) {
Row() {
Text(`${index}`)
}.width('100%').height('50vp')
}
.backgroundColor(color)
})
}

offset
这里和bootstrp的很像,栅格子组件相对于前一个子组件的偏移列数,默认为0。
- 当类型为number时,子组件偏移相同列数。
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
...
GridRow() {
ForEach(this.bgColors, (color, index) => {
GridCol({ offset: 2 }) {
Row() {
Text('' + index)
}.width('100%').height('50vp')
}
.backgroundColor(color)
})
}

栅格默认分成12列,每一个子组件默认占1列,偏移2列,每个子组件及间距共占3列,一行放四个子组件。
offset也支持六种不同尺寸(xs, sm, md, lg, xl, xxl)设备中子组件所占列数设置,各个尺寸下数值可不同。
@State bgColors: Color[] = [Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Pink, Color.Grey, Color.Blue, Color.Brown];
...
GridRow() {
ForEach(this.bgColors, (color, index) => {
GridCol({ offset: { xs: 1, sm: 2, md: 3, lg: 4 } }) {
Row() {
Text('' + index)
}.width('100%').height('50vp')
}
.backgroundColor(color)
})
}

order
子组件排列次序
- 当子组件不设置order或者设置相同的order, 子组件按照代码顺序展示
- 当子组件设置不同的order时,order较小的组件在前,较大的在后。
当类型为number时,子组件在任何尺寸下排序次序一致。
GridRow() {
GridCol({ order: 4 }) {
Row() {
Text('1')
}.width('100%').height('50vp')
}.backgroundColor(Color.Red)
GridCol({ order: 3 }) {
Row() {
Text('2')
}.width('100%').height('50vp')
}.backgroundColor(Color.Orange)
GridCol({ order: 2 }) {
Row() {
Text('3')
}.width('100%').height('50vp')
}.backgroundColor(Color.Yellow)
GridCol({ order: 1 }) {
Row() {
Text('4')
}.width('100%').height('50vp')
}.backgroundColor(Color.Green)
}

相对布局(RelativeContainer)
概述:
RelativeContainer为采用相对布局的容器,支持容器内部的子元素设置相对位置关系。子元素支持指定兄弟元素作为锚点,也支持指定父容器作为锚点,基于锚点做相对位置布局。下图是一个RelativeContainer的概念图,图中的虚线表示位置的依赖关系。
子元素并不完全是上图中的依赖关系。比如,Item4可以以Item2为依赖锚点,也可以以RelativeContainer父容器为依赖锚点。
- 锚点:通过锚点设置当前元素基于哪个元素确定位置
- 对齐方式:通过对齐方式,设置当前元素是基于锚点的上中下对齐,还是基于锚点的左中右对齐
设置依赖关系
锚点设置
锚点设置是指设置子元素相对于父元素或兄弟元素的位置依赖关系。
在水平方向上,可以设置left、middle、right的锚点。在竖直方向上,可以设置top、center、bottom的锚点。
了明确定义锚点,必须为RelativeContainer及其子元素设置ID,用于指定锚点信息。ID默认为“__container__”,其余子元素的ID通过id属性设置。未设置ID的子元素在RelativeContainer中不会显示。
- RelativeContainer父组件为锚点,__container__代表父容器的id。
RelativeContainer() {
Row()
// 添加其他属性
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
left: { anchor: '__container__', align: HorizontalAlign.Start }
})
.id("row1")
Row()
...
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
right: { anchor: '__container__', align: HorizontalAlign.End }
})
.id("row2")
}
...

- 以子元素为锚点。
RelativeContainer() {
...
top: { anchor: 'row1', align: VerticalAlign.Bottom },
...
}
.width(300).height(300)
.margin({ left: 20 })
.border({ width: 2, color: '#6699FF' })

设置相对于锚点的对齐位置
设置了锚点之后,可以通过align设置相对于锚点的对齐位置。
在水平方向上,对齐位置可以设置为HorizontalAlign.Start、HorizontalAlign.Center、HorizontalAlign.End。
在竖直方向上,对齐位置可以设置为VerticalAlign.Top、VerticalAlign.Center、VerticalAlign.Bottom。
场景实例
相对布局内的子元素相对灵活,只要在RelativeContainer容器内,均可以通过alignRules进行相应的位置移动。
@Entry
@Component
struct Index {
build() {
Row() {
RelativeContainer() {
Row()
.width(100)
.height(100)
.backgroundColor('#FF3333')
.alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top }, //以父容器为锚点,竖直方向顶头对齐
middle: { anchor: '__container__', align: HorizontalAlign.Center } //以父容器为锚点,水平方向居中对齐
})
.id('row1') //设置锚点为row1
Row() {
Image($r('app.media.icon'))
}
.height(100).width(100)
.alignRules({
top: { anchor: 'row1', align: VerticalAlign.Bottom }, //以row1组件为锚点,竖直方向底端对齐
left: { anchor: 'row1', align: HorizontalAlign.Start } //以row1组件为锚点,水平方向开头对齐
})
.id('row2') //设置锚点为row2
Row()
.width(100)
.height(100)
.backgroundColor('#FFCC00')
.alignRules({
top: { anchor: 'row2', align: VerticalAlign.Top }
})
.id('row3') //设置锚点为row3
Row()
.width(100)
.height(100)
.backgroundColor('#FF9966')
.alignRules({
top: { anchor: 'row2', align: VerticalAlign.Top },
left: { anchor: 'row2', align: HorizontalAlign.End },
})
.id('row4') //设置锚点为row4
Row()
.width(100)
.height(100)
.backgroundColor('#FF66FF')
.alignRules({
top: { anchor: 'row2', align: VerticalAlign.Bottom },
middle: { anchor: 'row2', align: HorizontalAlign.Center }
})
.id('row5') //设置锚点为row5
}
.width(300).height(300)
.border({ width: 2, color: '#6699FF' })
}
.height('100%').margin({ left: 30 })
}
}

总结
到这里我们把栅格布局(GridRow/GridCol)和相对布局(RelativeContainer)介绍完了;
这里重点注意栅格布局,在响应式开发中常用的方案之一,鸿蒙的一次开发多端部署会用到的方案之一。
栅格布局的提供了很高的的灵活行,我们可以领利用breakpoints对不同尺寸的屏幕进行断点操作,从而大大提升我们在多端响应式布局的灵活的操纵性;
栅格布局可以利用colums自定义列数。默认是12。跟bootstrap一样。
相对布局可以让我们对具体的某个元素进行对象定位操作。
结语
至此,UI系列本篇文章的内容结束了。文章有不对或不完整的地方,望多指点;
望更多小伙伴们加入harmonyOS开发大家庭,壮大生态圈,让鸿蒙更强更好。
如果对你学习有所帮助,还请点赞、评论、收藏、关注、分享;
希望可爱你动动小手关注订阅,一起进步,期待三连支持;
更多推荐
所有评论(0)