鸿蒙UI(ArkUI-方舟UI框架)
参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/arkts-layout-development-overview-V13
ArkUI简介
ArkUI(方舟UI框架)为应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。
两种开发范式
- 声明式开发范式
采用基于TypeScript声明式UI语法扩展而来的ArkTS语言,从组件、动画和状态管理三个维度提供UI绘制能力 - 类Web开发范式
采用经典的HML、CSS、JavaScript三段式开发方式,即使用HML标签文件搭建布局、使用CSS文件描述样式、使用JavaScript文件处理逻辑。该范式更符合于Web前端开发者的使用习惯,便于快速将已有的Web应用改造成方舟UI框架应用
UI开发(ArkTS声明式开发范式)
1、概述
基于ArkTS的声明式开发范式的方舟开发框架是一套开发极简、高性能、支持跨设备的UI开发框架,提供了构建应用UI所必需的能力,主要包括:
- ArkTS
- 布局
- 组件
- 页面路由和组件导航
- 图形
- 动画
- 交互事件
- 自定义能力
2、开发流程
学习ArkTS > 开发布局 > 添加组件 > 设置组件导航和页面路由 > 使用文本 > 使用弹窗 > 显示图形 > 使用动画 > 绑定事件 > 使用自定义能力 > 使用镜像能力 > 支持适老化 > 主题设置 > 使用UI上下文接口操作界面 > 使用NDK接口构建UI
3、通用规则
-
默认单位
表示长度的入参单位默认为vp,即入参为number类型、以及Length和Dimension类型中的number单位为vp。 -
异常值处理
输入的参数为异常(undefined,null或无效值)时,处理规则如下:(1)对应参数有默认值,按默认值处理;
(2)对应参数无默认值,该参数对应的属性或接口不生效。
开发布局
1、布局概述
1)布局结构
2)布局元素组成
3)如何选择布局
声明式UI提供了以下10种常见布局,开发者可根据实际应用场景选择合适的布局进行页面开发。
布局 | 应用场景 |
---|---|
线性布局(Row、Column) | 如果布局内子元素超过1个时,且能够以某种方式线性排列时优先考虑此布局 |
层叠布局(Stack) | 组件需要有堆叠效果时优先考虑此布局。层叠布局的堆叠效果不会占用或影响其他同容器内子组件的布局空间。例如Panel作为子组件弹出时将其他组件覆盖更为合理,则优先考虑在外层使用堆叠布局。 |
弹性布局(Flex) | 弹性布局是与线性布局类似的布局方式。区别在于弹性布局默认能够使子组件压缩或拉伸。在子组件需要计算拉伸或压缩比例时优先使用此布局,可使得多个容器内子组件能有更好的视觉上的填充效果。 |
相对布局(RelativeContainer) | 相对布局是在二维空间中的布局方式,不需要遵循线性布局的规则,布局方式更为自由。通过在子组件上设置锚点规则(AlignRules)使子组件能够将自己在横轴、纵轴中的位置与容器或容器内其他子组件的位置对齐。设置的锚点规则可以天然支持子元素压缩、拉伸、堆叠或形成多行效果。在页面元素分布复杂或通过线性布局会使容器嵌套层数过深时推荐使用。 |
栅格布局(GridRow、GridCol) | 栅格是多设备场景下通用的辅助定位工具,可将空间分割为有规律的栅格。栅格不同于网格布局固定的空间划分,可以实现不同设备下不同的布局,空间划分更随心所欲,从而显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。推荐内容相同但布局不同时使用。 |
媒体查询(@ohos.mediaquery) | 媒体查询可根据不同设备类型或同设备不同状态修改应用的样式。例如根据设备和应用的不同属性信息设计不同的布局,以及屏幕发生动态改变时更新应用的页面布局。 |
列表(List) | 使用列表可以高效地显示结构化、可滚动的信息。在ArkUI中,列表具有垂直和水平布局能力和自适应交叉轴方向上排列个数的布局能力,超出屏幕时可以滚动。列表适合用于呈现同类数据类型或数据类型集,例如图片和文本。 |
网格(Grid) | 网格布局具有较强的页面均分能力、子元素占比控制能力。网格布局可以控制元素所占的网格数量、设置子元素横跨几行或者几列,当网格容器尺寸发生变化时,所有子元素以及间距等比例调整。推荐在需要按照固定比例或者均匀分配空间的布局场景下使用,例如计算器、相册、日历等。 |
轮播(Swiper) | 轮播组件通常用于实现广告轮播、图片预览等。 |
选项卡(Tabs) | 选项卡可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量。 |
4)布局位置
position、offset等属性影响了布局容器相对于自身或其他组件的位置。
定位能力 | 使用场景 | 实现方法 |
---|---|---|
绝对定位 | 对于不同尺寸的设备,使用绝对定位的适应性会比较差,在屏幕的适配上有缺陷 | 使用position实现绝对定位,设置元素左上角相对于父容器左上角偏移位置。在布局容器中,设置该属性不影响父容器布局,仅在绘制时进行位置调整。 |
相对定位 | 相对定位不脱离文档流,即原位置依然保留,不影响元素本身的特性,仅相对于原位置进行偏移。 | 使用offset可以实现相对定位,设置元素相对于自身的偏移量。设置该属性,不影响父容器布局,仅在绘制时进行位置调整。 |
5)对子元素的约束
-
拉伸:容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域
-
缩放:子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变
-
占比:子组件的宽高按照预设的比例,随祖先容器组件发生变化
-
隐藏:隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏
2、构建布局
1)线性布局 (Row/Column)
概述
线性布局(LinearLayout)是开发中最常用的布局,通过线性容器Row和Column构建。线性布局是其他布局的基础,其子元素在线性方向上(水平方向和垂直方向)依次排列。线性布局的排列方向由所选容器组件决定,Column容器内子元素按照垂直方向排列,Row容器内子元素按照水平方向排列。根据不同的排列方向,开发者可选择使用Row或Column容器创建线性布局。
图1 Column(列,竖着走)容器内子元素排列示意图
图2 Row(行,横着走)容器内子元素排列示意图
布局子元素在排列方向上的间距
在布局容器内,可以通过space属性设置排列方向上子元素的间距,使各子元素在排列方向上有等间距效果。
-
Column容器内排列方向上的间距
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%')
-
Row容器内排列方向上的间距
Row({ space: 35 }) { Text('space: 35').fontSize(15).fontColor(Color.Gray) Row().width('10%').height(150).backgroundColor(0xF5DEB3) Row().width('10%').height(150).backgroundColor(0xD2B48C) Row().width('10%').height(150).backgroundColor(0xF5DEB3) }.width('90%')
布局子元素在交叉轴上的对齐方式(alignItems)
在布局容器内,可以通过alignItems属性设置子元素在交叉轴(排列方向的垂直方向)上的对齐方式。
Column({}) {
}.width('100%').alignItems(HorizontalAlign.Start)
其中,交叉轴为垂直方向时,取值为VerticalAlign类型,水平方向取值为HorizontalAlign类型。
Column({}) {
}.width('100%').alignItems(VerticalAlign.Start)
-
HorizontalAlign.Start:子元素在水平方向左对齐。
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)')
-
HorizontalAlign.Center:子元素在水平方向居中对齐。
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.Center).backgroundColor('rgb(242,242,242)')
- HorizontalAlign.End:子元素在水平方向右对齐。
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.End).backgroundColor('rgb(242,242,242)')
-
VerticalAlign.Top:子元素在垂直方向顶部对齐。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).alignItems(VerticalAlign.Top).backgroundColor('rgb(242,242,242)')
-
VerticalAlign.Center:子元素在垂直方向居中对齐。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).alignItems(VerticalAlign.Center).backgroundColor('rgb(242,242,242)')
-
VerticalAlign.Bottom:子元素在垂直方向底部对齐。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).alignItems(VerticalAlign.Bottom).backgroundColor('rgb(242,242,242)')
布局子元素在主轴上的排列方式(justifyContent)
在布局容器内,可以通过justifyContent属性设置子元素在容器主轴上的排列方式。
可以从主轴起始位置开始排布,也可以从主轴结束位置开始排布,或者均匀分割主轴的空间。
1、Column容器内子元素在垂直方向上的排列
-
justifyContent(FlexAlign.Start):元素在垂直方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。
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)
-
justifyContent(FlexAlign.Center):元素在垂直方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。
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.Center)
-
justifyContent(FlexAlign.End):元素在垂直方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐。
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.End)
-
justifyContent(FlexAlign.SpaceBetween):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。
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.SpaceBetween)
-
justifyContent(FlexAlign.SpaceAround):垂直方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。
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.SpaceAround)
-
justifyContent(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.SpaceEvenly)
1、Row容器内子元素在水平方向上的排列
-
justifyContent(FlexAlign.Start):元素在水平方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Start)
-
justifyContent(FlexAlign.Center):元素在水平方向中心对齐,第一个元素与行首的距离与最后一个元素与行尾距离相同。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.Center)
-
justifyContent(FlexAlign.End):元素在水平方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.End)
-
justifyContent(FlexAlign.SpaceBetween):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素与行首对齐,最后一个元素与行尾对齐。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceBetween)
-
justifyContent(FlexAlign.SpaceAround):水平方向均匀分配元素,相邻元素之间距离相同。第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceAround)
-
justifyContent(FlexAlign.SpaceEvenly):水平方向均匀分配元素,相邻元素之间的距离、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。
Row({}) { Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) Column() { }.width('20%').height(30).backgroundColor(0xD2B48C) Column() { }.width('20%').height(30).backgroundColor(0xF5DEB3) }.width('100%').height(200).backgroundColor('rgb(242,242,242)').justifyContent(FlexAlign.SpaceEvenly)
自适应拉伸
在线性布局下,常用空白填充组件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%') } } }
竖屏:
横屏:
自适应延伸
自适应延伸是指在不同尺寸设备下,当页面的内容超出屏幕大小而无法完全显示时,可以通过滚动条进行拖动展示。这种方法适用于线性布局中内容无法一屏展示的场景。通常有以下两种实现方式。
-
在List中添加滚动条:当List子项过多一屏放不下时,可以将每一项子元素放置在不同的组件中,通过滚动条进行拖动展示。可以通过scrollBar属性设置滚动条的常驻状态,edgeEffect属性设置拖动到内容最末端的回弹效果。
-
使用Scroll组件:在线性布局中,开发者可以进行垂直方向或者水平方向的布局。当一屏无法完全显示时,可以在Column或Row组件的外层包裹一个可滚动的容器组件Scroll来实现可滑动的线性布局。
垂直方向布局中使用Scroll组件:
@Entry @Component struct ScrollExample { scroller: Scroller = new Scroller(); private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; build() { Scroll(this.scroller) { Column() { ForEach(this.arr, (item?:number|undefined) => { if(item){ Text(item.toString()) .width('90%') .height(150) .backgroundColor(0xFFFFFF) .borderRadius(15) .fontSize(16) .textAlign(TextAlign.Center) .margin({ top: 10 }) } }, (item:number) => item.toString()) }.width('100%') } .backgroundColor(0xDCDCDC) .scrollable(ScrollDirection.Vertical) // 滚动方向为垂直方向 .scrollBar(BarState.On) // 滚动条常驻显示 .scrollBarColor(Color.Gray) // 滚动条颜色 .scrollBarWidth(10) // 滚动条宽度 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 } }
水平方向布局中使用Scroll组件:
@Entry @Component struct ScrollExample { scroller: Scroller = new Scroller(); private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; build() { Scroll(this.scroller) { Row() { ForEach(this.arr, (item?:number|undefined) => { if(item){ Text(item.toString()) .height('90%') .width(150) .backgroundColor(0xFFFFFF) .borderRadius(15) .fontSize(16) .textAlign(TextAlign.Center) .margin({ left: 10 }) } }) }.height('100%') } .backgroundColor(0xDCDCDC) .scrollable(ScrollDirection.Horizontal) // 滚动方向为水平方向 .scrollBar(BarState.On) // 滚动条常驻显示 .scrollBarColor(Color.Gray) // 滚动条颜色 .scrollBarWidth(10) // 滚动条宽度 .edgeEffect(EdgeEffect.Spring) // 滚动到边沿后回弹 } }
2)层叠布局 (Stack)
概述
层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠,容器中的子元素依次入栈,后一个子元素覆盖前一个子元素,子元素可以叠加,也可以设置位置。
层叠布局具有较强的页面层叠、位置定位能力,其使用场景有广告、卡片层叠效果等。
开发布局
Stack组件为容器组件,容器内可包含各种子元素。其中子元素默认进行居中堆叠。子元素被约束在Stack下,进行自己的样式定义以及排列。
// xxx.ets
let MTop:Record<string,number> = { 'top': 50 }
@Entry
@Component
struct StackExample {
build() {
Column(){
Stack({ }) {
Column(){}.width('90%').height('100%').backgroundColor('#ff58b87c')
Text('text').width('60%').height('60%').backgroundColor('#ffc3f6aa')
Button('button').width('30%').height('30%').backgroundColor('#ff8ff3eb').fontColor('#000')
}.width('100%').height(150).margin(MTop)
}
}
}
对齐方式
Stack组件通过alignContent参数实现位置的相对移动。如图2所示,支持九种对齐方式。
// 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值越大,显示层级越高,即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)
场景实例
使用层叠布局快速搭建页面。
@Entry
@Component
struct StackSample {
private arr: string[] = ['APP1', 'APP2', 'APP3', 'APP4', 'APP5', 'APP6', 'APP7', 'APP8'];
build() {
Stack({ alignContent: Alignment.Bottom }) {
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.arr, (item:string) => {
Text(item)
.width(100)
.height(100)
.fontSize(16)
.margin(10)
.textAlign(TextAlign.Center)
.borderRadius(10)
.backgroundColor(0xFFFFFF)
}, (item:string):string => item)
}.width('100%').height('100%')
Flex({ justifyContent: FlexAlign.SpaceAround, alignItems: ItemAlign.Center }) {
Text('联系人').fontSize(16)
Text('设置').fontSize(16)
Text('短信').fontSize(16)
}
.width('50%')
.height(50)
.backgroundColor('#16302e2e')
.margin({ bottom: 15 })
.borderRadius(15)
}.width('100%').height('100%').backgroundColor('#CFD0CF')
}
}
3)弹性布局(Flex)
概述
弹性布局(Flex)提供更加有效的方式对容器中的子元素进行排列、对齐和分配剩余空间。常用于页面头部导航栏的均匀分布、页面框架的搭建、多行数据的排列等。
容器默认存在主轴与交叉轴,子元素默认沿主轴排列,子元素在主轴方向的尺寸称为主轴尺寸,在交叉轴方向的尺寸称为交叉轴尺寸。
基本概念
- 主轴:Flex组件布局方向的轴线,子元素默认沿着主轴排列。主轴开始的位置称为主轴起始点,结束位置称为主轴结束点。
- 交叉轴:垂直于主轴方向的轴线。交叉轴开始的位置称为交叉轴起始点,结束位置称为交叉轴结束点。
布局方向
在弹性布局中,容器的子元素可以按照任意方向排列。通过设置参数direction,可以决定主轴的方向,从而控制子元素的排列方向。
-
FlexDirection.Row(默认值):主轴为水平方向,子元素从起始端沿着水平方向开始排布。
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)
-
FlexDirection.RowReverse:主轴为水平方向,子元素从终点端沿着FlexDirection. Row相反的方向开始排布。
Flex({ direction: FlexDirection.RowReverse }) { 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)
-
FlexDirection.Column:主轴为垂直方向,子元素从起始端沿着垂直方向开始排布。
Flex({ direction: FlexDirection.Column }) { Text('1').width('100%').height(50).backgroundColor(0xF5DEB3) Text('2').width('100%').height(50).backgroundColor(0xD2B48C) Text('3').width('100%').height(50).backgroundColor(0xF5DEB3) } .height(70) .width('90%') .padding(10) .backgroundColor(0xAFEEEE)
-
FlexDirection.ColumnReverse:主轴为垂直方向,子元素从终点端沿着FlexDirection. Column相反的方向开始排布。
Flex({ direction: FlexDirection.ColumnReverse }) { Text('1').width('100%').height(50).backgroundColor(0xF5DEB3) Text('2').width('100%').height(50).backgroundColor(0xD2B48C) Text('3').width('100%').height(50).backgroundColor(0xF5DEB3) } .height(70) .width('90%') .padding(10) .backgroundColor(0xAFEEEE)
布局换行
弹性布局分为单行布局和多行布局。默认情况下,Flex容器中的子元素都排在一条线(又称“轴线”)上。wrap属性控制当子元素主轴尺寸之和大于容器主轴尺寸时,Flex是单行布局还是多行布局。在多行布局时,通过交叉轴方向,确认新行排列方向。
-
FlexWrap. NoWrap(默认值):不换行。如果子元素的宽度总和大于父元素的宽度,则子元素会被压缩宽度。
Flex({ wrap: FlexWrap.NoWrap }) { Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) Text('2').width('50%').height(50).backgroundColor(0xD2B48C) Text('3').width('50%').height(50).backgroundColor(0xF5DEB3) } .width('90%') .padding(10) .backgroundColor(0xAFEEEE)
-
FlexWrap. Wrap:换行,每一行子元素按照主轴方向排列。
Flex({ wrap: FlexWrap.Wrap }) { Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) Text('2').width('50%').height(50).backgroundColor(0xD2B48C) Text('3').width('50%').height(50).backgroundColor(0xD2B48C) } .width('90%') .padding(10) .backgroundColor(0xAFEEEE)
-
FlexWrap. WrapReverse:换行,每一行子元素按照主轴反方向排列。
Flex({ wrap: FlexWrap.WrapReverse}) { Text('1').width('50%').height(50).backgroundColor(0xF5DEB3) Text('2').width('50%').height(50).backgroundColor(0xD2B48C) Text('3').width('50%').height(50).backgroundColor(0xF5DEB3) } .width('90%') .padding(10) .backgroundColor(0xAFEEEE)
主轴对齐方式(justifyContent)
通过justifyContent参数设置子元素在主轴方向的对齐方式。
交叉轴对齐方式(alignItems)
容器和子元素都可以设置交叉轴对齐方式,且子元素设置的对齐方式优先级较高。
-
ItemAlign.Auto:使用Flex容器中默认配置
let SWh:Record<string,number|string> = { 'width': '90%', 'height': 80 } Flex({ alignItems: ItemAlign.Auto }) { Text('1').width('33%').height(30).backgroundColor(0xF5DEB3) Text('2').width('33%').height(40).backgroundColor(0xD2B48C) Text('3').width('33%').height(50).backgroundColor(0xF5DEB3) } .size(SWh) .padding(10) .backgroundColor(0xAFEEEE)
-
ItemAlign.Start:交叉轴方向首部对齐。
let SWh:Record<string,number|string> = { 'width':'90%','height':80} Flex({alignItems: ItemAlign.Start}){ Text('1').width('33%').height(30).backgorunColor(0xF5DEB3) Text('2').width('33%').height(40).backgroundColor(0xD2B48C) Text('3').width('33%').height(50).backgroundColor(0xF5DEB3) } .size(SWh) .padding(0) .backgroundColor(0xAFEEEE)
-
ItemAlign.Center:交叉轴方向居中对齐。
let SWh:Record<string,number|string> = { 'width': '90%', 'height': 80 } Flex({ alignItems: ItemAlign.Center }) { Text('1').width('33%').height(30).backgroundColor(0xF5DEB3) Text('2').width('33%').height(40).backgroundColor(0xD2B48C) Text('3').width('33%').height(50).backgroundColor(0xF5DEB3) } .size(SWh) .padding(10) .backgroundColor(0xAFEEEE)
-
ItemAlign.End:交叉轴方向底部对齐。
let SWh:Record<string,number|string> = { 'width': '90%', 'height': 80 } Flex({ alignItems: ItemAlign.End }) { Text('1').width('33%').height(30).backgroundColor(0xF5DEB3) Text('2').width('33%').height(40).backgroundColor(0xD2B48C) Text('3').width('33%').height(50).backgroundColor(0xF5DEB3) } .size(SWh) .padding(10) .backgroundColor(0xAFEEEE)
-
ItemAlign.Stretch:交叉轴方向(竖向)拉伸填充,在未设置尺寸时,拉伸到容器尺寸。
let SWh:Record<string,number|string> = { 'width': '90%', 'height': 80 }
Flex({ alignItems: ItemAlign.Stretch }) {
Text('1').width('33%').backgroundColor(0xF5DEB3)
Text('2').width('33%').backgroundColor(0xD2B48C)
Text('3').width('33%').backgroundColor(0xF5DEB3)
}
.size(SWh)
.padding(10)
.backgroundColor(0xAFEEEE)
- 子元素设置交叉轴对齐
子元素的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:子元素各行与交叉轴起点对齐
Flex({ justifyContent: FlexAlign.SpaceBetween, wrap: FlexWrap.Wrap, alignContent: FlexAlign.Start }) { Text('1').width('30%').height(20).backgroundColor(0xF5DEB3) Text('2').width('60%').height(20).backgroundColor(0xD2B48C) Text('3').width('40%').height(20).backgroundColor(0xD2B48C) Text('4').width('30%').height(20).backgroundColor(0xF5DEB3) Text('5').width('20%').height(20).backgroundColor(0xD2B48C) } .width('90%') .height(100) .backgroundColor(0xAFEEEE)
-
FlexAlign.Center:子元素各行在交叉轴方向居中对齐
-
FlexAlign.End:子元素各行与交叉轴终点对齐。
-
FlexAlign.SpaceBetween:子元素各行与交叉轴两端对齐,各行间垂直间距平均分布
-
FlexAlign.SpaceAround:子元素各行间距相等,是元素首尾行与交叉轴两端距离的两倍。
-
FlexAlign.SpaceEvenly: 子元素各行间距,子元素首尾行与交叉轴两端距离都相等。
-