鸿蒙新特性——Swiper 轮播图组件详解
一、引言
轮播图是移动应用中最高频的 UI 模式之一——打开电商 App 首页,顶部横幅轮播正滚动着促销活动;天气 App 中,城市卡片左右滑动切换;社交 App 的开屏引导页,一页页解释着新功能。轮播组件不仅承载着核心内容的展示,更是应用的"第一印象",直接影响用户的操作直觉和浏览体验。
传统开发中,实现轮播需要组合 ScrollView + PageIndicator + Timer 定时器 + 手势处理等多套机制。这些组件之间需要精确协调——定时器启动/停止的时机、手势与自动播放的互斥、最后一页滑动后是否回到第一页——任一环节的疏忽都会导致体验 Bug(如双指滑动触发自动翻页、快速滑动导致页面错位)。
而 HarmonyOS 提供了 Swiper 组件——一个专用于轮播的容器组件。它在一套 API 中集成了内容滑动(水平/垂直)、自动播放(autoPlay)、无限循环(loop)、指示器(圆点/数字/无)、动画控制(duration/curve),以及 SwiperController 手动控制切换。开发者只需声明 Swiper 的属性,将子页面放入容器,即可获得一个功能完备的轮播组件。
本文通过一个"轮播图展廊"Demo 深入讲解 Swiper 组件的核心用法:如何设置自动播放和切换间隔?圆点指示器与数字指示器如何切换?无限循环如何开启?以及如何通过 SwiperController 实现手动导航和缩略图导航。
阅读完本文,你将能够:
- 使用 Swiper 组件构建轮播图
- 配置 autoPlay、loop、interval 等自动播放属性
- 使用 Indicator.dot() 和 Indicator.digit() 定制指示器样式
- 使用 SwiperController 编程控制翻页
- 构建完整的轮播图展廊应用
二、Swiper 组件 API 总览
2.1 构造函数
Swiper(controller?: SwiperController) {
// 子组件——每个直接子组件为一个轮播页
}
| 参数 | 类型 | 说明 |
|---|---|---|
controller |
SwiperController | 控制器,用于编程控制翻页(prev/next/jumpTo) |
Swiper 是一个容器组件,其每个直接子组件代表一个轮播页面。子组件通常使用 ForEach 从数据数组动态生成。如果传入 SwiperController 实例,即可在代码中调用 showNext()、showPrevious()、changeIndex(idx) 等方法控制翻页。
2.2 链式方法
// 是否自动播放
.autoPlay(value: boolean): SwiperAttribute
// 是否无限循环(最后一页滑到第一页,第一页滑到最后一页)
.loop(value: boolean): SwiperAttribute
// 自动播放间隔(毫秒),仅 autoPlay=true 时生效
.interval(value: number): SwiperAttribute
// 滑动动画时长(毫秒)
.duration(value: number): SwiperAttribute
// 是否垂直滑动(默认 false 即水平滑动)
.vertical(value: boolean): SwiperAttribute
// 动画曲线
.curve(value: Curve | string): SwiperAttribute
// 指示器样式
.indicator(value: DotIndicator | DigitIndicator | boolean): SwiperAttribute
// 翻页变化回调(返回当前页索引)
.onChange(callback: (index: number) => void): SwiperAttribute
// 动画开始回调
.onAnimationStart(callback: (index: number) => void): SwiperAttribute
| 方法 | 说明 |
|---|---|
.autoPlay(boolean) |
是否自动轮播,false 时仅响应手势滑动 |
.loop(boolean) |
是否无限循环。true 时首尾相连;false 时到达边界无法继续滑动 |
.interval(number) |
自动播放间隔,单位毫秒。默认 3000ms。仅 autoPlay=true 时有效 |
.duration(number) |
切换动画的时长,单位毫秒。建议 200~600ms |
.vertical(boolean) |
true 即垂直方向滑动(如抖音信息流),默认 false(水平滑动) |
.curve(Curve) |
动画缓动曲线,默认 Curve.Linear。可设 Curve.Ease / Curve.FastOutSlowIn 等 |
.indicator(...) |
设置指示器。支持 DotIndicator(圆点)、DigitIndicator(数字比例)、false(隐藏) |
.onChange(Callback<number>) |
页码变化回调,返回当前页索引。用于绑定外部状态(如缩略图高亮) |
.onAnimationStart(Callback<number>) |
切换动画开始时触发,可用于动画开始前的前置逻辑 |
2.3 Indicator 类型
Swiper 内置了两种指示器样式:
// 圆点指示器
Indicator.dot()
.itemWidth(8) // 圆点宽度(vp)
.itemHeight(8) // 圆点高度(vp)
.selectedItemWidth(16) // 选中圆点宽度
.selectedItemHeight(8) // 选中圆点高度
.color('#CCCCCC') // 未选中颜色
.selectedColor('#1677FF') // 选中颜色
.left(0) // 距左侧距离
.right(12) // 距右侧距离
.top(0) // 距顶部距离
.bottom(12) // 距底部距离
// 数字指示器
Indicator.digit()
.fontColor('#FFFFFF') // 文字颜色
.selectedFontColor('#FFFFFF') // 选中文字颜色
.digitFont({ size: 12 }) // 字体
.selectedDigitFont({ size: 14 })
.right(12)
.bottom(12)
| 指示器类型 | 视觉效果 | 适用场景 |
|---|---|---|
Indicator.dot() |
一排小圆点,选中项高亮放大 | 内容型轮播(banner、引导页、图片浏览) |
Indicator.digit() |
“1 / 5” 格式的数字比例 | 图片浏览器、相册详情 |
false |
无指示器 | 自定义指示器、仅手势滑动的场景 |
2.4 SwiperController 方法
interface SwiperController {
showNext(): void; // 切换到下一页
showPrevious(): void; // 切换到上一页
changeIndex(value: number): void; // 切换到指定索引页
finishAnimation(): void; // 停止当前动画
}
SwiperController 是 Swiper 组件与外部逻辑之间的桥梁。Demo 中的上一页/下一页按钮、缩略图导航均通过控制器实现。注意:changeIndex(index) 会触发过渡动画,而直接修改 Swiper 内部状态不经过控制器则可能跳过动画。
2.5 Swiper 与 Tabs 的区别
| 特性 | Swiper | Tabs |
|---|---|---|
| 核心用途 | 内容轮播(广告、引导页、图片浏览) | 页面切换(Tab 导航) |
| 切换方式 | 手势滑动 + 自动播放 + 编程控制 | 点击 Tab 标签 + 手势滑动 |
| 指示器 | dot / digit 内置样式 | TabBar 自定义标签 |
| 循环 | loop 属性支持 | 不直接支持循环 |
| 自动播放 | autoPlay + interval 支持 | 不支持 |
简言之:需要自动轮播、循环切换的场景(banner、引导页、图片浏览)用 Swiper;需要 Tab 导航切换的场景(首页/消息/我的)用 Tabs。
三、Demo 设计:轮播图展廊
3.1 功能概述
Demo 是一个"轮播图展廊"应用,模拟内容型应用中的 banner 横幅轮播功能:
- 主轮播区:5 张彩色内容卡片(220vp 高度),每张展示标题、副标题和页码,支持手势滑动切换
- 自动播放:默认开启,每 3 秒自动翻页,可随时切换开关状态
- 无限循环:最后一页右滑回到第一页,第一页左滑滑到最后一页
- 指示器切换:圆点 → 数字 → 隐藏,三种指示器样式实时切换
- 切换间隔:2 秒 / 3 秒 / 5 秒三档可选
- 手动导航:上一页 / 下一页按钮,列表点击跳转
- 缩略导航条:主轮播下方彩色进度条,点击直接跳转
- 页面列表:所有轮播页面清单,当前页高亮显示
3.2 交互点
| # | 交互 | 说明 |
|---|---|---|
| 1 | 手势滑动轮播 | 左右滑动切换轮播页面,onChange 更新当前索引 |
| 2 | 自动播放开关 | Switch 切换自动播放,开启时按 interval 定时翻页 |
| 3 | 指示器切换 | 切换圆点/数字/隐藏三种指示器样式,实时反映在轮播上 |
| 4 | 手动导航 | 上一页/下一页按钮 + 缩略条点击 + 列表点击,均通过 SwiperController 控制 |
四、完整代码实现

4.1 数据模型与状态
interface SlideData {
title: string;
subtitle: string;
bgColor: string;
accentColor: string;
}
@State currentIndex: number = 0;
@State autoPlayOn: boolean = true;
@State useDigit: boolean = false;
@State showIndicator: boolean = true;
@State loopOn: boolean = true;
@State intervalMs: number = 3000;
private swiperCtrl: SwiperController = new SwiperController();
private slides: SlideData[] = [
{ title: '鸿蒙新特性', subtitle: '探索 HarmonyOS NEXT 最新 API 和组件', bgColor: '#1677FF', accentColor: '#FFFFFF' },
{ title: '原生开发', subtitle: '纯鸿蒙原生应用,极致性能体验', bgColor: '#52C41A', accentColor: '#FFFFFF' },
{ title: '跨平台方案', subtitle: '一套代码,多端统一运行', bgColor: '#FF9800', accentColor: '#FFFFFF' },
{ title: '高性能渲染', subtitle: 'ArkUI 声明式框架,流畅 60fps', bgColor: '#9C27B0', accentColor: '#FFFFFF' },
{ title: '安全可信', subtitle: '系统级安全防护,数据全程加密', bgColor: '#FF4D4F', accentColor: '#FFFFFF' }
];
每条轮播数据包含标题、副标题、背景色和装饰色。SwiperController 实例在组件初始化时创建,传递给 Swiper 组件后即可在回调方法中调用翻页控制。五个 @State 变量分别控制自动播放状态、指示器类型、循环模式和切换间隔。
4.2 主轮播区
Swiper(this.swiperCtrl) {
ForEach(this.slides, (slide: SlideData, idx: number) => {
Column() {
Text(slide.title)
.fontSize(28)
.fontColor(slide.accentColor)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 10 })
Text(slide.subtitle)
.fontSize(14)
.fontColor(slide.accentColor.concat('CC')) // 副标题半透明
Text((idx + 1).toString().concat(' / ', this.slides.length.toString()))
.fontSize(11)
.fontColor(slide.accentColor.concat('88')) // 页码更透明
.margin({ top: 20 })
}
.width('100%')
.height(220)
.justifyContent(FlexAlign.Center)
.backgroundColor(slide.bgColor)
}, (slide: SlideData, idx: number) => slide.title)
}
.autoPlay(this.autoPlayOn)
.loop(this.loopOn)
.interval(this.intervalMs)
.duration(400)
.indicator(this.showIndicator ?
(this.useDigit ?
Indicator.digit().right(12).bottom(12) :
Indicator.dot().bottom(12)) :
false)
.onChange((index: number) => { this.currentIndex = index; })
逐行解析:
ForEach生成页面:5 张卡片,每张填满 100% 宽度和 220vp 高度,内容垂直居中.autoPlay(this.autoPlayOn):绑定自动播放开关。autoPlayOn为 true 时定时翻页,false 时仅响应手势.loop(this.loopOn):无限循环开关。开启后首尾相连,最后一页继续滑动回到第一页.interval(this.intervalMs):自动播放间隔,默认 3000ms。仅当 autoPlay 为 true 时生效.duration(400):翻页动画 400ms。值越小切换越快,值越大过渡越平滑.indicator(...):动态选择指示器——this.useDigit为 true 时显示数字指示器(“1/5”),否则显示圆点。this.showIndicator为 false 时隐藏(传入 false).onChange(...):页码变化时更新currentIndex,驱动缩略导航条和页面列表的高亮状态
4.3 缩略导航条
Row() {
ForEach(this.slides, (slide: SlideData, idx: number) => {
Row()
.width(40)
.height(4)
.borderRadius(2)
.backgroundColor(idx === this.currentIndex ? slide.bgColor : '#E8E8E8')
.margin({ left: 4, right: 4 })
.onClick(() => { this.swiperCtrl.changeIndex(idx); })
}, (slide: SlideData, idx: number) => slide.title)
}
.width('100%')
.justifyContent(FlexAlign.Center)
.margin({ top: 14 })
缩略导航条位于主轮播下方,由一排 40×4vp 的圆角条组成。当前页对应的条显示为该页背景色,其余为浅灰色。点击任意条调用 this.swiperCtrl.changeIndex(idx) 跳转到对应页面——这是"编程控制翻页"的典型用法。
4.4 播放控制区
// 自动播放开关
Row() {
Text('自动播放')
.fontSize(14).fontColor('#1a1a2e').fontWeight(FontWeight.Medium)
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.autoPlayOn })
.selectedColor('#1677FF')
.onChange((value: boolean) => { this.autoPlayOn = value; })
}
// 无限循环
Row() {
Text('无限循环')
.fontSize(14).fontColor('#1a1a2e').fontWeight(FontWeight.Medium)
.layoutWeight(1)
Toggle({ type: ToggleType.Switch, isOn: this.loopOn })
.selectedColor('#1677FF')
.onChange((value: boolean) => { this.loopOn = value; })
}
两个 Switch 开关分别控制自动播放和无限循环。关闭自动播放后轮播不会自动翻页但仍可手势滑动;关闭无限循环后到达边界时无法继续滑动(第一页无法滑到最后一页)。
指示器类型三选一按钮(圆点/数字/隐藏)和切换间隔三选一按钮(2s/3s/5s)使用统一的预设值选择器模式——选中项蓝色背景白色文字,未选中项灰色背景。
4.5 手动导航按钮
Row() {
Text('◀ 上一页')
.fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Medium)
.padding({ top: 10, bottom: 10, left: 20, right: 20 })
.borderRadius(10).backgroundColor('#1677FF')
.onClick(() => { this.swiperCtrl.showPrevious(); })
Blank()
Text('下一页 ▶')
.fontSize(14).fontColor('#FFFFFF').fontWeight(FontWeight.Medium)
.padding({ top: 10, bottom: 10, left: 20, right: 20 })
.borderRadius(10).backgroundColor('#1677FF')
.onClick(() => { this.swiperCtrl.showNext(); })
}
.width('100%')
两个按钮分别调用 showPrevious() 和 showNext(),提供了手势滑动之外的另一种切换方式。这对于以下场景尤为重要:老年用户不习惯手势滑动;展示型大屏(平板/车机)不方便手势操作;自动化演示场景需要程序控制翻页。
4.6 页面列表
ForEach(this.slides, (slide: SlideData, idx: number) => {
Row() {
Column() {
Text(slide.title)
.fontSize(15)
.fontColor(this.currentIndex === idx ? slide.bgColor : '#1a1a2e')
.fontWeight(this.currentIndex === idx ? FontWeight.Bold : FontWeight.Medium)
Text(slide.subtitle)
.fontSize(11).fontColor('#9999AA')
.margin({ top: 2 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
if (this.currentIndex === idx) {
Row()
.width(8).height(8).borderRadius(4)
.backgroundColor(slide.bgColor)
}
}
.width('100%')
.padding({ top: 12, bottom: 12, left: 4, right: 4 })
.border({ width: { bottom: 0.5 }, color: '#F2F3F5' })
.onClick(() => { this.swiperCtrl.changeIndex(idx); })
}, (slide: SlideData, idx: number) => slide.title)
页面列表展示所有 5 张轮播卡片的标题和副标题。当前页标题显示为该页背景色并加粗,右侧显示一个 8×8vp 的实心圆点作为标记。点击任意行跳转到对应页面。这是第三种导航方式——与缩略导航条互补,帮助用户在冗长的轮播列表中快速定位目标页面。
五、关键技术点详解
5.1 autoPlay 与 interval 的协作机制
autoPlay 是自动播放的总开关,interval 是两次切换之间的等待时间(毫秒)。两者的协作逻辑:
autoPlay = false:无论interval设为多少,都不会自动翻页。用户只能通过手势滑动或编程控制翻页autoPlay = true:每隔interval毫秒自动调用一次翻页。翻页方向由当前滑动方向决定(水平模式下默认向右翻)
默认 interval 为 3000ms。实际选择 interval 时应考虑:内容信息量(信息量大需要更长的阅读时间 → 5000ms+)、页面数量(页面越多,用户浏览一轮的时间越长)、业务需求(促销 banner 需要快速曝光多个活动 → 2000ms)。
Demo 中提供 2s/3s/5s 三档可选,让用户直观感受不同间隔的轮播节奏差异。
5.2 loop 与边界行为
.loop(true) 打开无限循环后,Swiper 内部会做两件事:
- 首尾相连:在第一页继续向左滑动(调用
showPrevious())会直接跳到最后一页,反之亦然 - 页面复用:循环模式下 Swiper 不会创建无限个页面实例——它通过内部的页面缓存池复用页面节点,保证内存使用可控
.loop(false) 关闭循环后:
- 在第一页时"上一页"按钮(
showPrevious())无效 - 在最后一页时自动播放停止(如果有
autoPlay) - 手势滑动到边界时出现回弹效果
Demo 中的"无限循环"开关绑定了 this.loopOn,用户关闭后可以立即体验边界限制的区别——尝试在第一页按"上一页"按钮,Swip er 将无响应。
5.3 指示器的定位与定制
Indicator.dot() 和 Indicator.digit() 都提供 .left()、.right()、.top()、.bottom() 四个定位属性,用于在轮播容器内放置指示器。默认值:
.dot()默认.bottom(12)水平居中(居中逻辑由 Swiper 内部处理).digit()默认.right(12).bottom(12)右下角
指示器定位使用相对于 Swiper 容器边界的偏移距离,不受轮播页面内容影响。这意味着即使轮播页背景色不同,指示器的位置始终固定。
圆点指示器的视觉定制包括尺寸(.itemWidth/.itemHeight)、间距(.itemSpace)、颜色(.color/.selectedColor)和选中项尺寸(.selectedItemWidth/.selectedItemHeight)。Demo 中使用默认样式以保持简洁,实际项目中可根据设计规范进行定制。
5.4 SwiperController 的使用时机
SwiperController 提供了三种方法:showNext()、showPrevious()、changeIndex(idx)。这些方法可以在任何事件回调中调用(如 onClick),但需要注意:
- 控制器必须在组件构建前创建:
new SwiperController()放在@State或private变量初始化阶段,不能放在build()方法内——否则每次重建都会创建新实例,导致控制器引用失效 - 循环模式下的索引处理:在
loop = true时调用changeIndex(0)总会跳转到第一页的实际内容(而不是循环后的某个副本) - 动画会排队执行:快速连续调用
showNext()时,Swiper 会将每次翻页请求排队,依次执行动画——不会出现页面跳过或动画混乱
Demo 中三种导航方式(手动按钮、缩略条、列表点击)都通过控制器实现,展示了"相同控制器,多种触发方式"的设计模式。
5.5 性能考量:大量页面的处理
对于轮播页面数量很多(如 20+ 张商品图片)的场景,每个页面作为一个独立的子组件,渲染过多页面会影响首屏加载速度。优化策略:
-
懒加载模式:Swiper 默认只创建当前页和相邻页的组件节点(内部缓存池),并非一次性创建所有页面。这个行为类似于 Flutter 的 PageView 和 Android 的 ViewPager2
-
使用图片懒加载:如果每页包含大图,结合
Image.syncLoad(false)(异步加载默认值)让图片在页面即将显示时才加载,而非一次性加载所有图片 -
控制 duration 时长:
.duration()设置过短(< 100ms)会造成视觉闪烁,设置过长(> 1000ms)会导致用户等待不耐烦。推荐 300~500ms 的过渡时长,Demo 中使用 400ms -
避免在 onChange 中执行繁重操作:
onChange在每次翻页时触发,如果回调中执行大量计算或网络请求,会导致滑动卡顿。应保持onChange内的逻辑轻量(如仅更新状态变量)
5.6 方向模式:水平 vs 垂直
.vertical(boolean) 控制滑动方向。false(默认)为水平滑动,适用于横幅轮播、引导页、图片浏览器。true 为垂直滑动,适用于全屏信息流、短视频、卡片式浏览。
垂直模式下,指示器的 .left()/.right() 定位属性对应的物理边不变(仍相对于屏幕的左右),但 .top()/.bottom() 对应垂直方向。如果指示器放在侧边(如 .right(12) 且 .vertical(true)),圆点会呈纵向排列。
Demo 中未使用垂直模式以保持 Demo 的聚焦性,但在实际项目(如短视频类应用)中,垂直 Swiper 是核心交互组件。
六、运行效果
6.1 初始状态
进入"轮播图展廊"页面,顶部深色标题栏显示"轮播图展廊",下方白色信息卡片介绍 Swiper 组件。主轮播区(220vp 高度)展示第 1 张蓝色卡片"鸿蒙新特性 — 探索 HarmonyOS NEXT 最新 API 和组件",底部显示圆点指示器(5 个圆点,第一个高亮)。缩略导航条第一个条为蓝色,其余为灰色。
三秒后自动切换到绿色"原生开发"页面,圆点指示器第 2 个高亮,缩略条第 2 个变绿。AutoPlay 开关默认开启状态(绿色 Switch)。
6.2 手势滑动
手指向左滑动轮播区 → 页面切换到下一页,onChange 更新 currentIndex,指示器和缩略条同步变化。向右滑动切换到上一页。手势滑动时自动播放的计时器会重置(从当前页重新计算 interval)。
6.3 切换指示器
点击"数字"按钮 → 圆点指示器消失,右下角出现数字指示器"2 / 5"(当前在第 2 页时)。再次点击"隐藏"→ 指示器完全消失,轮播区仅显示页面内容。点击"圆点"→ 恢复圆点指示器。三种指示器切换流畅,轮播本身不闪烁不重建。
6.4 手动导航
点击"上一页"按钮 → 轮播切换到上一张卡片,动画 400ms。快速连续点击"下一页"按钮多次 → 每次翻页动画依次执行,不跳页不混乱。点击缩略导航条第 4 个灰色条 → 轮播直接跳转到"高性能渲染"页面。
6.5 关闭自动播放与循环
关闭"自动播放"开关 → 轮播停止自动翻页,但手势滑动和按钮导航仍然有效。关闭"无限循环"开关 → 在"安全可信"(最后一页)点击"下一页"无反应。重新开启循环 → 最后一页点击"下一页"即可跳回"鸿蒙新特性"(第一页)。
6.6 切换间隔
将切换间隔从 3s 改为 2s → 轮播加速至每 2 秒翻页一次,节奏加快。改为 5s → 每页停留时间增长,适合信息量更大的卡片内容。切换间隔变更时自动播放的计时器立即重置。
七、总结
本文通过一个"轮播图展廊"实战 Demo,深入讲解了 HarmonyOS Swiper 轮播组件的核心用法:
- 基础轮播:Swiper 容器 + ForEach 生成子页面 + 手势滑动切换
- 自动播放:
.autoPlay(true)+.interval(ms)实现定时翻页,Switch 开关控制启停 - 无限循环:
.loop(true)实现首尾相连,关闭后边界回弹 - 指示器:
Indicator.dot()(圆点,适合内容轮播)和Indicator.digit()(数字,适合图片浏览),通过.indicator(false)隐藏 - 编程控制:
SwiperController.showNext()/.showPrevious()/.changeIndex(idx)实现手动导航、缩略条跳转和列表定位 - 动画定制:
.duration(ms)控制切换动画快慢,.curve()调整缓动曲线
Swiper 将"内容滑动 + 自动播放 + 指示器 + 循环 + 编程控制"整合进一套声明式 API,开发者只需关注轮播页面的内容和配置参数,而不需要处理定时器生命周期、手势冲突、页面缓存等底层细节。希望本文能帮助你在实际项目中高效运用 Swiper 组件。
本文基于 HarmonyOS NEXT API 24 编写,代码经 DevEco Studio 6.1.1 编译验证通过。
更多推荐



所有评论(0)