ArkUI-布局
- 布局概述
- 布局元素的组成
- 如何选择布局
- 布局位置
- 对子元素的约束
- 线性布局
- 部分属性与使用方式
- 层叠布局
- 部分属性与使用方式
- 弹性布局
- 基本概念
- 布局方向
- 布局换行
- 主轴对齐方式
- 交叉轴对齐方式
- 容器设置交叉轴对齐方式
- 子元素设置交叉轴对齐方式
- 内容对齐
- 自适应拉伸
布局概述
布局元素的组成
- 组件区域:表示组件的大小,width、height属性用于设置组件区域的大小。
- 组件内容区:组件区域减去组件的border值,表示组件内容或子组件进行测算时的最大值。
- 组件内容:组件内容区减去padding值,表示组件内容本身占用的大小。
- 组件布局边界:组件区域加上margin的大小。
如何选择布局
ArkUI提供了9种常见布局
布局 | 引用场景 |
---|---|
线性布局(Row、Column) | 如果布局内子元素超过一个,并且能够以某种线性方式进行排列的,优先考虑该布局 |
层叠布局(Stack) | 组件如果需要堆叠效果的优先考虑此布局,子组件在该布局内是堆叠的,不会占用或者影响其他子组件的布局空间 |
弹性布局(Flex) | 类似于线性布局,能够使子组件压缩或者拉伸,获得更好的视觉填充效果 |
相对布局(RelativeContainer) | 通过对子组件设置锚点规则(AlignRules)使子组件能够将自己在横轴、纵轴中的位置于容器或者容器内的其他子组件的位置对齐。 |
栅格布局(GridRow、GridCol) | 栅格布局可以将空间分割为有规律的栅格,不同于网格布局的固定空间划分。栅格布局可以实现不同设备下不同的布局,显著降低适配不同屏幕尺寸的开发成本。 |
媒体查询(@ohos.mediaquery) | 媒体查询可以根据不同的设备类型或者同设备的不同状态修改应用的样式,如屏幕方向改变,重绘布局,这部分后边会展开讲一下。 |
列表(List) | |
网格(Grid) | |
轮播(Swiper) | |
选项卡(Tabs) |
布局位置
定位能力 | 使用场景 | 实现方式 |
---|---|---|
绝对定位 | 对于不同尺寸的设备,使用绝对定位适应性较差 | 使用position 实现绝对定位,设置元素左上角相对于父容器左上角的偏移位置,不影响父布局,仅在绘制时进行位置调整。 |
相对定位 | 相对于原位置进行便宜,不影响元素本身的特性 | 使用offset 实现相对定位,设置元素相对于自身的偏移量,不影响父布局,仅在绘制时进行位置调整。 |
对子元素的约束
对子元素的约束能力 | 使用场景 | 实现方式 |
---|---|---|
拉伸 | 容器组件尺寸发生变化时,增加或者减少的空间全部分配给组件内指定区域 | flexGrow 基于父容器的剩余空间分配来控制组件拉伸,flexShrink 设置父容器的压缩尺寸来控制组件压缩。 |
缩放 | 父容器尺寸变化时,子组件按照预设的宽高比进行缩放 | aspectRatio 指定当前组件的宽高比(width/height) |
占比 | 子组件的宽高按照预设的比例,随父容器进行变化 | 两种实现方式:1.将子组件的宽高设置为父容器宽高的百分比 2.使用layoutWeight 属性,使子组件自适应占满剩余空间 |
隐藏 | 隐藏能力指的是,容器内的子组件,随着父容器的尺寸变化,按照预定的优先级显示或者是隐藏,相同优先级的组件,同时显示或者隐藏 | 通过displayPriority 属性来控制组件的显示和隐藏 |
线性布局
部分属性与使用方式
space :设置子元素在排列方向上的间距。
Column({ space: 20 }) {Text('space: 20').fontSize(15).fontColor(Color.Gray).width('90%')Row().width('90%').height(50).backgroundColor(0xF5DEB3)Row().width('90%').height(50).backgroundColor(0xD2B48C)Row().width('90%').height(50).backgroundColor(0xF5DEB3)
}.width('100%')
alignItems:设置子元素在交叉轴上的对齐方式。交叉轴为垂直方向时,取值为VerticalAlign
,交叉轴为水平方向时,取值为HorizontalAlign
。
Column({}) {Column() {}.width('80%').height(50).backgroundColor(0xF5DEB3)Column() {}.width('80%').height(50).backgroundColor(0xD2B48C)Column() {}.width('80%').height(50).backgroundColor(0xF5DEB3)
}.width('100%').alignItems(HorizontalAlign.Start).backgroundColor('rgb(242,242,242)')
justifyContent:子元素在容器主轴上的排列方式。
FlexAlign.Start
:元素向首端对齐,后续的元素向前一个元素对齐
FlexAlign.Center
:第一个元素距首端与最后一个元素距尾端距离一致。
FlexAlign.End
:元素向尾端对齐,前一个元素向后一个元素对齐
FlexAlign.SpaceBetween
:均匀分配元素,相邻元素之间的距离是相等的,第一个元素与首端对齐,最后一个元素与尾部对齐。
FlexAlign.SpaceAround
:均匀分配元素,相邻元素之间的距离是相等的,第一个元素与首端距离、最后一个元素与尾部距离是相邻元素之间距离的一半。
FlexAlign.SpaceEvenly
:均匀分配元素,相邻元素之间的距离是相等的,第一个元素与首端距离,最后一个元素与尾部距离,相邻元素之间的距离都是相等的。
水平布局和垂直布局的使用方式和效果是一致的。
使用示例:
Column({}) {Column() {}.width('80%').height(50).backgroundColor(0xF5DEB3)Column() {}.width('80%').height(50).backgroundColor(0xD2B48C)Column() {}.width('80%').height(50).backgroundColor(0xF5DEB3)
}.width('100%').height(300).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Start)
效果图:
自适应拉伸:在线性布局下,常用空白填充组件Blank
,在容器主轴方向自动填充空白空间,达到自适应拉伸效果。Row和Column作为容器,只需要添加宽高为百分比,当屏幕宽高发生变化时,会产生自适应效果。
@Entry
@Component
struct BlankExample {build() {Column() {Row() {Text('Bluetooth').fontSize(18)Blank()Toggle({ type: ToggleType.Switch, isOn: true })}.backgroundColor(0xFFFFFF).borderRadius(15).padding({ left: 12 }).width('100%')}.backgroundColor(0xEFEFEF).padding(20).width('100%')}
}
竖屏:
横屏:
自适应缩放:自适应缩放是指子元素随容器尺寸的变化而按照预设的比例自动调整尺寸,适应各种不同大小的设备。在线性布局中,可以使用以下两种方法实现自适应缩放。
-
父容器尺寸确定时,使用layoutWeight属性设置子元素和兄弟元素在主轴上的权重,忽略元素本身尺寸设置,使它们在任意尺寸的设备下自适应占满剩余空间。
@Entry @Component struct layoutWeightExample {build() {Column() {Text('1:2:3').width('100%')Row() {Column() {Text('layoutWeight(1)').textAlign(TextAlign.Center)}.layoutWeight(1).backgroundColor(0xF5DEB3).height('100%')Column() {Text('layoutWeight(2)').textAlign(TextAlign.Center)}.layoutWeight(2).backgroundColor(0xD2B48C).height('100%')Column() {Text('layoutWeight(3)').textAlign(TextAlign.Center)}.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%')}.backgroundColor(0xffd306).height('30%')Text('2:5:3').width('100%')Row() {Column() {Text('layoutWeight(2)').textAlign(TextAlign.Center)}.layoutWeight(2).backgroundColor(0xF5DEB3).height('100%')Column() {Text('layoutWeight(5)').textAlign(TextAlign.Center)}.layoutWeight(5).backgroundColor(0xD2B48C).height('100%')Column() {Text('layoutWeight(3)').textAlign(TextAlign.Center)}.layoutWeight(3).backgroundColor(0xF5DEB3).height('100%')}.backgroundColor(0xffd306).height('30%')}} }
竖屏:
横屏:
-
父容器尺寸确定时,使用百分比设置子元素和兄弟元素的宽度,使他们在任意尺寸的设备下保持固定的自适应占比。
@Entry @Component struct WidthExample {build() {Column() {Row() {Column() {Text('left width 20%').textAlign(TextAlign.Center)}.width('20%').backgroundColor(0xF5DEB3).height('100%')Column() {Text('center width 50%').textAlign(TextAlign.Center)}.width('50%').backgroundColor(0xD2B48C).height('100%')Column() {Text('right width 30%').textAlign(TextAlign.Center)}.width('30%').backgroundColor(0xF5DEB3).height('100%')}.backgroundColor(0xffd306).height('30%')}} }
竖屏:
横屏:
层叠布局
部分属性与使用方式
alignContent:Stack支持9种对齐方式。
使用方式:Stack({ alignContent: Alignment.TopStart })
// xxx.ets
@Entry
@Component
struct StackExample {build() {Stack({ alignContent: Alignment.TopStart }) {Text('Stack').width('90%').height('100%').backgroundColor('#e1dede').align(Alignment.BottomEnd)Text('Item 1').width('70%').height('80%').backgroundColor(0xd2cab3).align(Alignment.BottomEnd)Text('Item 2').width('50%').height('60%').backgroundColor(0xc1cbac).align(Alignment.BottomEnd)}.width('100%').height(150).margin({ top: 5 })}
}
各对齐方式效果图如下:
Z序控制:Stack容器中子组件的显示层级关系可以通过Z序控制的zIndex属性改变,zIndex值越大,显示层级越高。
Stack({ alignContent: Alignment.BottomStart }) {Column() {Text('Stack子元素1').fontSize(20)}.width(100).height(100).backgroundColor(0xffd306).zIndex(2)Column() {Text('Stack子元素2').fontSize(20)}.width(150).height(150).backgroundColor(Color.Pink).zIndex(1)Column() {Text('Stack子元素3').fontSize(20)}.width(200).height(200).backgroundColor(Color.Grey)
}.width(350).height(350).backgroundColor(0xe0e0e0)
弹性布局
基本概念
Flex提供更加有效的对容器中子元素进行排列、对齐和分配剩余空间。常用于页面头部导航栏的均匀分布、页面框架的搭建、多行数据的排列等。
Flex默认存在主轴与交叉轴,子元素默认沿主轴排列,子元素在主轴方向的尺寸成为主轴尺寸,在交叉轴方向的尺寸成为交叉轴尺寸。
主轴:Flex组件布局方向的轴线,子元素默认沿着主轴排列。主轴开始的位置称为主轴的起点,结束的位置称为主轴结束点。
交叉轴:垂直于主轴方向的轴线。交叉轴开始的位置称为交叉轴起点,结束的位置称为交叉轴结束点。
布局方向
在Flex中,容器的子元素可以按照任意方向排列。通过设置参数direction
,可以改变主轴的方向。
- FlexDirection.Row:默认值
- FlexDirection.RowReverse:
- FlexDirection.Column:
- FlexDirection.ColumnReverse:
如图所示:
使用示例:
Flex({ direction: FlexDirection.Row }) {Text('1').width('33%').height(50).backgroundColor(0xF5DEB3)Text('2').width('33%').height(50).backgroundColor(0xD2B48C)Text('3').width('33%').height(50).backgroundColor(0xF5DEB3)
}
.height(70)
.width('90%')
.padding(10)
.backgroundColor(0xAFEEEE)
布局换行
Flex分为单行布局和多行布局,默认情况下是单行布局。可以通过参数warp
来控制。
- FlexWrap.NoWrap:默认值,不换行,如果子元素的宽度总和大于父元素的宽度,子元素会被压缩宽度。
- FlexWrap.Wrap:换行,每行子元素都按照主轴方向排列。
- FlexWrap.WrapReverse:换行,每行子元素都按照主轴的反方向排列。
主轴对齐方式
Flex通过justifyContent
参数设置主轴的对齐方式,与Row和Column一致。
- FlexAlign.Start:默认值
- FlexAlign.Center:
- FlexAlign.End:
- FlexAlign.SpaceBetween:
- FlexAlign.SpaceAround:
- FlexAlign.SpaceEvenly:
交叉轴对齐方式
容器和子元素都可以设置交叉轴的对齐方式,子元素设置的对齐方式优先级更高。
容器设置交叉轴对齐方式
Flex通过alignItems
参数设置子元素在交叉轴的对齐方式
- ItemAlign.Auto:默认项
- ItemAlign.Start:
- ItemAlign.Center:
- ItemAlign.End:
- ItemAlign.Strech:交叉轴方向填充拉伸,在未设置尺寸时,拉伸到容器尺寸。
- itemAlign.Baseline:交叉轴方向文本基本线对齐。
子元素设置交叉轴对齐方式
子元素通过alignSelf
属性也可以设置子元素在父容器交叉轴的对齐方式,会覆盖Flex中alignItems属性的配置。
示例:
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { // 容器组件设置子元素居中Text('alignSelf Start').width('25%').height(80).alignSelf(ItemAlign.Start).backgroundColor(0xF5DEB3)Text('alignSelf Baseline').alignSelf(ItemAlign.Baseline).width('25%').height(80).backgroundColor(0xD2B48C)Text('alignSelf Baseline').width('25%').height(100).backgroundColor(0xF5DEB3).alignSelf(ItemAlign.Baseline)Text('no alignSelf').width('25%').height(100).backgroundColor(0xD2B48C)Text('no alignSelf').width('25%').height(100).backgroundColor(0xF5DEB3)}.width('90%').height(220).backgroundColor(0xAFEEEE)
内容对齐
Flex可以通过alignContent
参数设置子元素在交叉轴剩余空间内的对齐方式,只有在多行Flex布局中生效。
- FlexAlign.Start:
- FlexAlign.Center:
- FlexAlign.End:
- FlexAlign.SpaceBetween:
- FlexAlign.SpacAround:
- FlexAlign.SpaceEvenly:
自适应拉伸
Flex尺寸过小时,通过子元素的一下属性设置其在父容器中的占比,达到自适应布局。
-
flexBasis:设置子元素在父容器主轴方向上的基准尺寸,如果设置了该属性,那么子项占用的空间为该属性所设置的值,如果没有设置改属性,则子项的空间为width/height的值。
Flex() {Text('flexBasis("auto")').flexBasis('auto') // 未设置width以及flexBasis值为auto,内容自身宽度.height(100).backgroundColor(0xF5DEB3)Text('flexBasis("auto")'+' width("40%")').width('40%').flexBasis('auto') //设置width以及flexBasis值auto,使用width的值.height(100).backgroundColor(0xD2B48C)Text('flexBasis(100)') // 未设置width以及flexBasis值为100,宽度为100vp.flexBasis(100) .height(100).backgroundColor(0xF5DEB3)Text('flexBasis(100)').flexBasis(100).width(200) // flexBasis值为100,覆盖width的设置值,宽度为100vp.height(100).backgroundColor(0xD2B48C) }.width('90%').height(120).padding(10).backgroundColor(0xAFEEEE)
-
flexGrow:设置父容器剩余空间分配给此属性所在控件的比例。用于分配父组件的剩余空间。
Flex() {Text('flexGrow(2)').flexGrow(2).width(100).height(100).backgroundColor(0xF5DEB3)Text('flexGrow(3)').flexGrow(3).width(100).height(100).backgroundColor(0xD2B48C)Text('no flexGrow').width(100).height(100).backgroundColor(0xF5DEB3) }.width(420).height(120).padding(10).backgroundColor(0xAFEEEE)
父容器宽度420vp,三个子元素原始宽度为100vp,左右padding为20vp,总和320vp,剩余空间100vp根据flexGrow值的占比分配给子元素,未设置flexGrow的子元素不参与“瓜分”。第一个元素以及第二个元素以2:3分配剩下的100vp。第一个元素为100vp+100vp * 2/5=140vp,第二个元素为100vp+100vp * 3/5=160vp。
-
flexShrink:当父容器空间不足时,子组件的压缩比例。
Flex({ direction: FlexDirection.Row }) {Text('flexShrink(3)').flexShrink(3).width(200).height(100).backgroundColor(0xF5DEB3)Text('no flexShrink').width(200).height(100).backgroundColor(0xD2B48C)Text('flexShrink(2)').flexShrink(2).width(200).height(100).backgroundColor(0xF5DEB3) }.width(400).height(120).padding(10).backgroundColor(0xAFEEEE)