1. 线性布局(Row/Column)
- 自适应拉伸:空白填充 Blank 组件可作为 Column 和 Row 容器的子组件,该组件不显示任何内容,并且会始终充满容器主轴方向上的剩余空间,达到自适应拉伸效果。
- 自适应缩放:layoutWeight 属性可用于 Column 和 Row 容器的子组件,其作用是配置子组件在主轴方向上的尺寸权重。配置该属性后,子组件沿主轴方向的尺寸设置(width或height)将失效,具体尺寸根据权重进行计算。
1.1. Column - 沿垂直方向布局容器
- 支持通用属性,如 alignItems,justifyContent,width,height,border 等。
- justifyContent() 设置子元素沿主轴方向的排列方式,参数类型为枚举类型 FlexAlign.
- alignItems() 设置子元素沿交叉轴方向的对齐方式,参数类型为枚举类型
HorizontalAlign
..backgroundBlurStyle(BlurStyle.Regular)
为当前组件提供一种在背景和内容之间的模糊能力。
Column({space: 5}){} // 创建一个column容器组件,设置子元素间的垂直间距为5,纵向布局元素垂直方向间距为5.
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.Center) //
1.2. Row - 沿水平方向布局容器
- 支持通用属性,如 alignItems,justifyContent,width,height,border 等。
- justifyContent() 设置子元素沿主轴方向的排列方式,参数类型为枚举类型 FlexAlign.
- alignItems() 设置子元素沿交叉轴方向的对齐方式,参数类型为枚举类型
VerticalAlign
.
Row({space: 5}){} // 横向布局元素间距
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Start)
2. 层叠布局(Stack)
- 将多个组件沿垂直于屏幕的方向堆叠在一起,类似于图层的叠加。
- 层叠布局可通过 Stack 容器组件实现,其子元素会按照其添加顺序依次叠加在一起,后添加的子元素位于先添加的子元素之上。
- 组件的参数类型为{ alignContent?: Alignment },
alignContent
用于设置子组件的对齐方式,该属性可通过枚举类型 Alignment 进行设置。- 子组件Z轴控制:Stack 容器的子组件的层级除了可按照添加顺序决定,还能通过 zIndex() 进行手动设置,zIndex 的值越大,层级越高。
- 子组件精确定位:Stack 容器的子组件可使用 position() 方法进行更精确的定位,该方法可设置子组件
左上角
相对于 Stack 容器左上角
的偏移量。
3. 弹性布局(Flex)
- 以弹性方式布局子组件的容器组件。
- alignItems() 设置子元素在交叉轴方向的对齐方式,参数类型为枚举类型
ItemAlign
。- alignContent() 设置多行子组件在交叉轴方向的排列方式,该属性的类型为枚举类型 FlexAlign。
3.1 子组件常用属性
- 交叉轴对齐:alignSelf() 方法可以单独设置子组件自己的交叉轴对齐方式,并且优先级高于Flex容器alignItems。参数类型同样也是枚举类型
ItemAlign
,各枚举值的含义也完全相同。- 自适应伸缩:子组件沿主轴方向的尺寸具有弹性。即子组件的大小能够随着Flex容器尺寸的变化而自动伸缩。相关属性有 flexShrink()、flexGrow()、flexBasis() 。
- flexShrink() 默认值1,当父容器空间不足时,子组件的压缩比例。
- flexGrow() 默认值0,用于“瓜分”父组件的剩余空间。
- flexBasis() 设置子组件在父容器主轴方向上的基准尺寸。如果设置了该值,则子项占用的空间为设置的值;如果没设置该属性,那子项的空间为width/height的值。
4. 网格布局(Grid/GridItem)
- Grid容器组件和子组件GridItem,用于构建网格布局。
4.1 Grid - 网格容器
- fr (fraction比例、分数) 的个数即网格布局的行或列数,fr 前面的数值大小,用于计算该行或列在网格布局宽度上的占比,最终决定该行或列的宽度。
- 行:rowsTemplate()
- 列:columnsTemplate()
Grid() {
ForEach(DataModel.getFirstGridData(), (item: ItemDate) => {
GridItem() {
Column() {
Image(item.img)
.width($r('app.float.home_homeCell_size'))
.height($r('app.float.home_homeCell_size'))
Text(item.title)
.fontSize($r('app.float.little_text_size'))
.margin({ top: $r('app.float.home_homeCell_margin') })
}
}
})
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr')
.columnsGap($r('app.float.home_grid_columnsGap'))
.rowsGap($r('app.float.home_grid_rowGap'))
4.2 GridItem - 网格容器中单项内容容器
- GridItem 组件支持横跨几行或者几列。
- 可以使用 rowStart()、rowEnd()、columnStart() 和columnEnd() 方法设置 GridItem 组件所占的单元格。
- Grid 容器中的行号和列号均从0开始。
- 行列间距:rowsGap()、.columnsGap() 属性,可以控制行列间距。
5. 列表布局(List/ListItem/ListItemGroup)
- ListItem 展示列表具体item,必须配合 List容器组件 来使用。
- scroller 参数用于绑定列表滚动控制器Scroller,Scroller可以控制列表的滚动。
private scroller: Scroller = new Scroller() build(){ List({space: 10, scroller: this.scroller}) Button() .onClick(() => { this.scroller.scrollEdge(Edge.Top) }) }
- listDirection() 方法可以设置列表的主轴方向,其参数类型为枚举类型 Axis
- alignListItem() 方法可以设置子组件在交叉轴方向的对齐方式,其参数类型为枚举类型 ListItemAlign
- divider() 属性可设置列表元素分割线样式。
.scrollBar()
方法可以设置滚动条状态,该方法的参数类型为枚举类型 BarState。onReachEnd(() => {})
事件:列表到底末尾位置时触发。
List边缘效果为弹簧效果时,划动经过末尾位置时触发一次,回弹回末尾位置时再触发一次。
6. 导航布局(Tabs/TabContent)
6.1 Tabs - 页签容器
- 通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
- 基本用法如下:
barPosition: BarPosition
设置Tabs的页签位置。默认值:BarPosition.Start.index: number
设置当前显示页签的索引。默认值:0.controller: TabsController
设置Tabs控制器。.vertical()
:用于设置导航栏是否垂直排列,参数为boolean类型,默认值:false。.barPosition()
:用于设置Tabs的页签位置,参数为枚举类型BarPosition,默认值:BarPosition.Start。.barMode()
:将页签设置为可滚动的,参数为枚举类型BarMode,默认值:BarMode.Fixed。
6.1.1 TabsController
- Tabs组件的控制器,用于控制Tabs组件进行页签切换。不支持一个TabsController控制多个Tabs组件。
- 导入对象
private tabsController: TabsController = new TabsController()
changeIndex(value: number): void
控制Tabs切换到指定页签。this.tabsController.changeIndex(this.currentTabIndex)
6.2. TabContent - 页签内容视图
- 仅在Tabs中使用,对应一个切换页签的内容视图。
TabContent()
组件表示每个页签的内容。其属性.tabBar()
表示其对应的页签。- 默认的页签只有文字内容,可以通过
@Builder
自定义导航栏实现图文并有的复杂页签。- 自定义页签的选中状态需要我们自己实现。
4.1 定义一个@State状态变量 currentIndex 表示当前选中的索引。
4.2 触发 Tabs 的 onChange((index) => {this.currentIndex = index}) 事件 or 调用控制器的changeIndex()
事件。
4.3 通过传入给定的页签下标0,1,2 与 currentIndex 做判断来实现选中的状态。
代码示例1
import { PracticePage } from './PracticePage'
@Entry
@Component
struct Index {
@State currentTabIndex: number = 0
private tabsController: TabsController = new TabsController()
build() {
Column() {
Tabs({ index: this.currentTabIndex, controller: this.tabsController }) {
TabContent() {
PracticePage()
}.tabBar(this.barBuilder(0, $r('app.media.normal_answer_icon'), $r('app.media.answer_icon'), '答题'))
TabContent() {
Text('圈子')
}
.tabBar(this.barBuilder(1, $r('app.media.normal_circleOfFriends_icon'), $r('app.media.circleOfFriends_icon'),
'圈子'))
TabContent() {
Text('我的')
}.tabBar(this.barBuilder(2, $r('app.media.normal_mine_icon'), $r('app.media.mine_icon'), '我的'))
}.tabsStyle()
// .onChange((index: number) => {
// this.currentTabIndex = index
// })
}
.height('100%')
.width('100%')
}
@Builder
barBuilder(tabBarIndex: number, icon: Resource, iconSelected: Resource, title: string) {
Column() {
Image(this.currentTabIndex === tabBarIndex ? iconSelected : icon).width(25).height(25)
Text(title).tabTitleStyle(this.currentTabIndex === tabBarIndex ? Color.Black : '#959595')
}
.onClick(() => {
this.currentTabIndex = tabBarIndex
this.tabsController.changeIndex(this.currentTabIndex)
})
}
}
@Extend(Tabs)
function tabsStyle() {
.vertical(false).barPosition(BarPosition.End).barMode(BarMode.Fixed)
}
@Extend(Text)
function tabTitleStyle(color: ResourceColor) {
.fontSize(10)
.fontColor(color)
.fontWeight(FontWeight.Medium)
.margin({ bottom: 2 })
}
代码示例2
// 导入Tabs组件的对象控制器
private controller: TabsController = new TabsController()
@Builder
TabBuilder(index: number, normalImg: Resource, selectedImg: Resource, title: string) {
Column() {
Image(index === this.currentIndex ? selectedImg : normalImg)
.width($r('app.float.mainPage_baseTab_size'))
.height($r('app.float.mainPage_baseTab_size'))
Text(title)
.margin({
top: $r('app.float.mainPage_baseTab_top')
})
.fontSize($r('app.float.main_Tab_fontSize'))
.fontColor(index === this.currentIndex ? $r('app.color.minePage_selected') : $r('app.color.minePage_normal'))
}
.justifyContent(FlexAlign.Center)
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.mainPage_barHeight'))
.onClick((index: number) => {
this.currentIndex = index
this.controller.changeIndex(this.currentIndex)
})
}
Tabs({
barPosition: BarPosition.End,
controller: this.controller
}) {
TabContent() {
Home()
}
.padding({
left: $r('app.float.mainPage_padding'),
right: $r('app.float.mainPage_padding')
})
.backgroundColor($r('app.color.minePage_backgroundColor'))
.tabBar(this.TabBuilder(
CommonConstants.HOME_TAB_INDEX,
$r('app.media.normal_home_icon'),
$r('app.media.home_icon'),
CommonConstants.HOME_TITLE
))
7. Scroll - 可滚动的容器组件
- 可滑动的容器组件,当子组件的布局尺寸超过父组件的视口时,内容可以滑动。
Scroll(scroller?: Scroller)
7.1 Scroller
- 可滑动容器组件的控制器,可以将此组件绑定至容器组件,然后通过它控制容器组件的滑动,目前支持绑定到 List、Scroll、ScrollBar上。
7.1.1 导入对象
private scroller: Scroller = new Scroller()
7.1.2 绑定至容器组件
List({ scroller: this.scroller }) {
ForEach(this.postInfoList, (item: PostInfo) => {
ListItem() {
PostItem({ post: item })
}
})
}
7.1.3 scrollTo
- 滑动到指定位置。
7.1.4 scrollEdge
- 滑动到容器边缘。
7.1.5 scrollPage
- 滑动到下一页或者上一页。
7.1.6 currentOffset
- 返回当前的滑动偏移量。
7.1.7 scrollToIndex
- 滑动到指定Index。
Button({ type: ButtonType.Circle }) {
Image($r('app.media.ic_ok3')).width(14).height(14)
}.width(40).height(40).backgroundColor(Color.White).opacity(.5)
.onClick(() => {
this.scroller.scrollToIndex(0)
})
8. Swiper - 滑块视图容器
- 提供子组件滑动轮播显示的能力
// 导入Swiper组件的对象控制器
private swiperController: SwiperController = new SwiperController()
Swiper(this.swiperController) {
ForEach(DataModel.getSwiperImages(), (item: Resource) => {
Image(item)
.width(CommonConstants.FULL_PARENT)
.height($r('app.float.home_swiper_height'))
.borderRadius($r('app.float.home_swiper_borderRadius'))
.objectFit(ImageFit.Contain)
})
}
.index(0) // 设置当前在容器中显示的子组件的索引值。默认值:0
.autoPlay(true) // 子组件是否自动播放.默认值:false
.interval(3000) // 使用自动播放时播放的时间间隔,单位为毫秒。默认值:3000
.indicator(false) // 是否启用导航点指示器。
.loop(true) // 是否开启循环。默认值:true
.duration(400) // 子组件切换的动画时长,单位为毫秒。默认值:400
.vertical(false) // 是否为纵向滑动。默认值:false
.itemSpace(0) // 设置子组件与子组件之间间隙.默认值:0
.displayCount(1) // 设置一页内元素显示个数。默认值:1
// 主轴方向上元素排列的模式,优先以displayCount设置的个数显示,displayCount未设置时本属性生效.默认值:SwiperDisplayMode.Stretch
.displayMode(SwiperDisplayMode.STRETCH) // Swiper滑动一页的宽度为Swiper组件自身的宽度。
.cachedCount(1) // 设置预加载子组件个数。默认值:1
.disableSwipe(false) // 禁用组件滑动切换功能。默认值:false
.curve(Curve.Linear) // 设置Swiper的动画曲线,默认为线性曲线
.effectMode(EdgeEffect.Spring) // 滑动效果
.margin({
top: $r('app.float.home_swiper_margin')
})
9. Counter - 计数器组件
- 计数器组件,提供相应的增加或者减少的计数操作。
- 可以包含子组件。
@state count: number = 1
Counter() {
Text(this.count.toString())
}
.onInc(() => this.count++)
.onDec(() => this.count--)
10. RelativeContainer
- 相对布局组件,用于复杂场景中元素对齐的布局。
- 子组件可以将容器或者其他子组件设为锚点
- 参与相对布局的容器内组件必须设置id,不设置id的组件不显示,容器id固定为__container__。
Row() {
RelativeContainer() {
Row().width(100).height(100)
.backgroundColor("#FF3333")
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
left: {anchor: "__container__", align: HorizontalAlign.Start}
})
.id("row1")
Row().width(100).height(100)
.backgroundColor("#FFCC00")
.alignRules({
top: {anchor: "__container__", align: VerticalAlign.Top},
right: {anchor: "__container__", align: HorizontalAlign.End}
})
.id("row2")
}
}