一、引言
- 鸿蒙OS的UI组件库提供了丰富的界面构建能力,本文精选5个高频使用组件,通过实际代码演示其核心功能:
- 这些组件可组合构建复杂界面,如电商首页(轮播图+九宫格+商品列表+导航栏+购物车角标)
二、Swiper组件:轮播图实现
核心功能
Swiper是一个滑动容器,允许用户通过水平或垂直滑动在多个子组件之间切换视图。它非常适合展示一组图片、卡片、引导页或任何需要分页展示的内容。
适用场景
- 产品/图片轮播图 (如 App 首页 Banner)。
- 应用启动时的引导页面。
- 多步骤表单的分步展示。
- 横竖方向的内容浏览视图。
简单实现
@Entry
@Component
struct NewsBanner {
build() {
//轮播图组件
Swiper() {
//播放的图片
Image($r('app.media.banner01'))
.width('100%')
.height(220)
Image($r('app.media.banner02'))
.width('100%')
.height(220)
Image($r('app.media.banner03'))
.width('100%')
.height(220)
}
.height(220)
.autoPlay(true) // 启用自动播放
.interval(3000) // 3秒切换间隔
.indicator(true) // 显示指示器
.loop(true) // 循环播放
}
}
Swiper的常用配置属性
-
index
: 设置初始显示的子组件索引(从0开始)。 -
autoPlay
: 是否自动轮播 (true
/false
)。 -
interval
: 自动轮播的时间间隔(毫秒)。 -
loop
: 是否循环轮播 (true
/false
)。 -
indicator
: 控制是否显示分页指示器(通常为小圆点)和其样式 (如SwiperIndicator
的属性:color
,selectedColor
,size
等)。 -
duration
: 滑动动画的持续时间(毫秒)。 -
vertical
: 滑动方向是否为垂直 (true
垂直 /false
水平)。
设置导航点样式
默认导航点样式为蓝色,形状为胶囊体,有时候我们需要其他的样式,这样我们就需要对导航点的样式进行修改,可以通过indicator属性设置。
调整导航点类型:
Swiper(){
// 略
}
// .indicator(false) // 关闭导航
// .indicator(Indicator.dot()) // 圆点指示器(默认)
// .indicator(Indicator.digit()) // 数字指示器
调整圆点指示器样式:
Swiper(){
// 略
}
.indicator(
Indicator.dot()
.left(10) //设置指示器位置
.top(10)
.itemWidth(20) // 设置指示器样式
.itemHeight(10)
.color(Color.Red)
.selectedItemWidth(30) // 设置选中时的样式
.selectedItemHeight(10)
.selectedColor(Color.White)
) // 圆点指示器
三、Grid组件:网格布局
核心功能
Grid组件提供灵活的多行多列网格布局能力。你可以精确控制列数、行高、列宽以及元素排列方式,非常适合构建整齐划一的图标列表、照片墙或商品列表。
适用场景
- 应用主菜单/功能图标区域。
- 图片相册缩略图视图。
- 商品展示列表。
- 卡片集合视图(以网格形式)。
简单实现
@Entry
@Component
struct Index {
build() {
Column() {
//网格布局
//容器组件 Grid(){ 子组件 GridItem(){ 只能有一个根组件 } }
Grid() {
GridItem() {
Text('1')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('2')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('3')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('4')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('5')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('6')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
}
.width('100%')
.height(200)
.columnsTemplate('1fr 2fr 1fr') // 设置网格列数 fr控制列数 数字控制份数
.rowsTemplate('1fr 1fr') // 设置网格行数 fr控制行数 数字控制份数
.columnsGap(10) // 设置列与列之间间隙
.rowsGap(10) //设置行与行之间间隙
}
.width('100%')
.height('100%')
}
}
Grid的常用配置属性
-
columnsTemplate
: 核心属性! 定义列的宽度规则。例如:'1fr 1fr'
(等宽两列),'200px 1fr 2fr'
(第一列固定200px,第二列占剩余空间1份,第三列占2份),'repeat(4, 1fr)'
(等宽4列)。(单独设置可以使内容垂直滚动) -
rowsTemplate
: 定义行的高度规则 (用法同columnsTemplate
)。(单独设置可以使内容水平滚动) -
columnsGap
: 列之间的间距。 -
rowsGap
: 行之间的间距。
合并行列
日常开发中除了大小相同的等比例网格布局,由不同大小的网格组成不均匀分布的网格布局场景在实际应用中也十分常见。
合并行:找到需要合并的第一个GridItem的位置,给他添加rowStart(数字1)和rowEnd(数字2)属性,合并的行数为:数字2-数字1。
合并列:找到需要合并的第一个GridItem的位置,给他添加columnStart(数字1)和columnEnd(数字2)属性,合并的行数为:数字2-数字1。
@Entry
@Component
struct Index {
build() {
Column() {
//网格布局
//容器组件 Grid(){ 子组件 GridItem(){ 只能有一个根组件 } }
Grid() {
//合并一二行
GridItem() {
Text('1')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
.rowStart(0)
.rowEnd(2)
//合并二三列
GridItem() {
Text('2')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
.columnStart(1)
.columnEnd(2)
GridItem() {
Text('3')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
GridItem() {
Text('4')
}
.width('100%')
.height('100%')
.backgroundColor('#4f7efb')
}
.width('100%')
.height(200)
.columnsTemplate('1fr 2fr 1fr') // 设置网格列数 fr控制列数 数字控制份数
.rowsTemplate('1fr 1fr') // 设置网格行数 fr控制行数 数字控制份数
.columnsGap(10) // 设置列与列之间间隙
.rowsGap(10) //设置行与行之间间隙
}
.width('100%')
.height('100%')
}
}
四、Scroll - 滚动视图容器
核心功能
Scroll组件为其内容提供可滚动的容器。当内容超过Scroll的视口大小时,用户可以滚动查看隐藏部分。它是构建超出屏幕范围内容页面的基础。
适用场景
- 任何需要显示内容长度超出容器高度的页面区域。
- 包裹长列表、复杂布局的视图。
- 需要监听滚动位置或实现特定滚动效果的地方。
简单实现
@Entry
@Component
struct Page01_Scroll {
build() {
Column({ space: 10 }) {
// Scroll 容器尺寸固定
// 内容横向超出 Scroll 即可滚动
Scroll() {
Column() {
Text('1')
.width('100%')
.height(100)
.backgroundColor(Color.Orange)
Text('2')
.width('100%')
.height(100)
.backgroundColor(Color.Gray)
Text('3')
.width('100%')
.height(100)
.backgroundColor(Color.Pink)
}
}
.width('100%')
.height(200)
.scrollBar(BarState.On) //滚动条状态 关闭滚动条
.scrollBarWidth(10) //滚动条宽度
.scrollBarColor(Color.Green) //滚动条颜色
.edgeEffect(EdgeEffect.Spring) //弹簧效果
}
.width('100%')
.height('100%')
}
}
Scroll的常用配置属性
-
scrollable
: 控制滚动方向 (ScrollDirection.Vertical
垂直 /ScrollDirection.Horizontal
水平 /ScrollDirection.None
禁用)。 -
scrollBar
: 控制滚动条显示策略 (BarState.Auto
自动显示 /BarState.On
始终显示 /BarState.Off
始终隐藏)。 -
edgeEffect
: 设置滚动到边界时的效果 (EdgeEffect.Spring
回弹 /EdgeEffect.Fade
渐隐 /EdgeEffect.None
无)。 -
scroller
: 关联一个滚动控制器 (Scroller
对象),用于以编程方式控制滚动位置(如滚动到指定位置、响应滚动状态)。 -
onScroll
: 滚动时持续触发的回调,可获取滚动偏移量(offset.x
,offset.y
)。
滚动控制器
日常开发中可能需要通过代码控制滚动,以及获取滚动的距离,比如
- 页面滚动超过一定距离,显示返回顶部,反之隐藏--获取滚动距离
- 点击返回顶部,返回顶部--代码控制滚动
这个时候就可以通过 Scroll 的控制器来实现
实现步骤:
- 实例化 Scroller的 控制器
- 绑定给 Scroll
- 调用 控制器的方法(scrollEdge) 控制滚动 以及 (currentOffset)获取滚动距离
onWillScroll事件
.onWillScroll(() => {
//页面滚动 会触发此事件
//获取页面滚动出去的距离
console.log('', this.scroller.currentOffset().xOffset) //获取水平滚出去的距离
console.log('', this.scroller.currentOffset().yOffset) //获取垂直滚出去的距离
})
通过控制器控制滚动结合onWillScroll事件结合可以实现滚动到顶部图标的功能
@Entry
@Component
struct Index3 {
@State isShow: boolean = false
// 1.创建控制器对象 Scroller
scroller: Scroller = new Scroller()
build() {
Column() {
Stack({ alignContent: Alignment.BottomEnd }) {
// 顶部滚动区域
// 2.绑定给组件
Scroll(this.scroller) {
Column() {
Image($r('app.media.scroll'))
}
}
.scrollBar(BarState.Off)
.width('100%')
.backgroundColor(Color.Orange)
.onWillScroll(() => {
//获取页面滚动的距离
let num: number = this.scroller.currentOffset().yOffset
//4.通过判断滚动的距离设置图标是否显示
if (num >= 400) {
this.isShow = true
} else {
this.isShow = false
}
})
if (this.isShow) {
Image($r('app.media.ic_jd_huo'))
.width(40)
.backgroundColor(Color.White)
.borderRadius(20)
.padding(5)// .margin({right:20,bottom:20})
.offset({ x: -20, y: -20 })
.onClick(() => {
// 3. 调用Scroller中的方法 实现页面滚动到边缘
this.scroller.scrollEdge(Edge.Top)
})
}
}
.layoutWeight(1)
// 底部 tabbar
Image($r('app.media.ic_jd_tab'))
.width('100%')
}
}
}
五、Tabs - 标签页切换器
核心功能
Tabs组件提供了一种在多个内容视图之间切换的标签式导航。它通常包含一个TabBar(标签栏)和一个TabContent(内容区)。用户点击标签切换不同内容视图。
适用场景
- 具有明显分类结构的内容导航(如“首页”、“发现”、“我的”)。
- 信息聚合应用中不同类目的切换。
- 详情页中不同维度的信息分页(如商品详情、参数、评论)。
简单实现
@Entry
@Component
struct Page07_TabsAttribute {
build() {
Tabs() {
// 内容
TabContent() {
Text('首页的内容')
.fontSize(30)
}
// tabBar
.tabBar('首页')
TabContent() {
Text('推荐的内容')
.fontSize(30)
}
.tabBar('推荐')
TabContent() {
Text('发现的内容')
.fontSize(30)
}
.tabBar('发现')
TabContent() {
Text('我的内容')
.fontSize(30)
}
.tabBar("我的")
}
.vertical(true) // 设置导航的方向 默认是false true为垂直
.barPosition(BarPosition.End) //设置导航位置 枚举 默认值start
.scrollable(false) // 设置页面是否可以滑动 默认值true false不能滑动
.animationDuration(4000) // 设置页面切换事件 单位毫秒
}
}
Tabs的常用配置属性
-
vertical: 属性即可调整导航为 水平 或 垂直
-
barPosition: 即可调整导航位置为 开头 或 结尾
-
scrollable: 即可调整是否允许 页面滑动切换
-
animationDuration: 设置动画时间 毫秒
-
barHeight: 设置tabBar的高度
-
divider: 设置tabBar和tebContent的分割线
-
barMode:设置 固定导航栏 或 滚动导航栏
自定义导航栏
TabBar 如果放在底部的话,一般会显示图形和文字,甚至有特殊的图标,而默认导航栏的样式是固定的,如果要实现此类效果,就需要 自定义tabBar。
实现自定义导航栏样式可以在tabBar中传入Builder构造器
Tabs() {
TabContent() {
// 内容略
}
.tabBar(this.tabBarBuilder())
}
@Builder
tabBarBuilder() {
// 自定义的Tabbar结构
}
在自定义导航栏样式后会发现原来的选中高亮效果会失效,要再实现这个效果需要:
1. 将当前导航栏下标(index)传入自定义构建函数中
2. 定义一个状态变量来存储点击的当前导航对应下标
3. 在onTabBarClick或onChange事件中,将点击的导航下标存储在状态变量中
4. 在自定义构建函数中, 使用三元表达式,进行判断
- 状态变量的值和当前下标的值是否一致
- 如果一致, 高亮 否则 显示默认效果
interface TabItems {
imgUrl: string
text: string
}
@Entry
@Component
struct Index {
@State tabItems: TabItems[] = [
{ imgUrl: 'app.media.ic_car', text: '购物车' },
{ imgUrl: 'app.media.ic_my', text: '我的' }
]
// 1. 定义状态变量存储页面下标
@State selectedIndex: number = 0
// 高亮核心 -> 页面下标和导航下标是否一致
build() {
Column() {
Tabs() {
ForEach(this.tabItems, (item: TabItems, index: number) => {
TabContent() {
Text(item.text)
// 3. index下标传递到builder函数中,index用来做导航下标
}
.tabBar(this.tabBarBuilder(item, index))
})
}
.barPosition(BarPosition.End)
.onChange((index) => {
//页面切换 执行此事件
//index 是切换的页面下标
// console.log('onChange', index)
// 2. 在事件中存储下标
this.selectedIndex = index
})
.onTabBarClick((index) => {
//导航点击就会触发的事件
//index 页面的下标
// console.log('onTabBarClick', index)
})
}
.width('100%')
.height('100%')
}
//自定义导航栏样式
@Builder
tabBarBuilder(ele: TabItems, index: number) {
Column({ space: 5 }) {
Image($r(ele.imgUrl))
.width(30)
// 4. 判断 存储的下标和传递的下标是否一致 一致高亮 否则不高亮
.fillColor(this.selectedIndex === index ? '#f40' : '#000')
Text(ele.text)
.fontSize(14)
.fontColor(this.selectedIndex === index ? '#f40' : '#000')
}
}
}
六、Badge - 标记通知
核心功能
Badge是一个轻量级的组件,用于在其子组件的右上角(或其他角)添加一个小型的标记(数字、点或文字),通常用于显示未读消息数、新消息提示、状态标记等。
适用场景
- 应用图标/功能按钮/头像上的未读消息计数(小红点+数字)。
- 标记“新”、“热”、“优惠”等特殊状态(文字或图标)。
- 需要引起用户注意的视觉提醒点。
简单实现
@Entry
@Component
struct Index {
build() {
Column({ space: 50 }) {
//角标组件(标记组件)
//显示数字
Badge({
count: 11,
style: {
fontSize: 20, //字体大写
badgeSize: 40, //角标大小
color: Color.Orange, //字体颜色
badgeColor: Color.Blue //角标颜色
},
position: BadgePosition.RightTop, //角标位置
maxCount: 10 //角标显示最大数,超过这个数会用+显示
}) {
Text('')
.width(60)
.height(60)
.border({ width: 1 })
}
//显示文字
Badge({
value: '上新',
style: { fontSize: 20, badgeSize: 40 }
}) {
Text('')
.width(60)
.height(60)
.border({ width: 1 })
}
}
.width('100%')
.height('100%')
}
}
Badge的常用属性
-
count
: 最常见属性。 设置显示的数字。当数值大于maxCount
时,显示${maxCount}+
。设为0
或< 0
时不显示数字。 -
maxCount
: 数字显示的上限(默认99)。 -
position
: 标记相对于子组件的位置(BadgePosition.RightTop
右上(默认)/BadgePosition.Right
右中 /BadgePosition.Left
左中等)。 -
style
: 设置标记的样式。-
color
: 标记背景色(通常是醒目的红色)。 -
fontSize
: 数字/文字的字体大小。 -
badgeSize
: 标记的大小(影响背景圆角形状)。 -
badgeColor
: 同上color
。
-
-
visible
: 控制标记是否可见 (true
/false
)。 -
value
: 如果不想显示数字,而是显示一个小圆点提示,可将count
设为undefined
或null
。或使用BadgeStatus
(仅Dot)。