HarmonyOS 6.1 实战:Swiper 轮播图与页面滑动详解

HarmonyOS 6.1 实战:Swiper 轮播图与页面滑动详解 前言Swiper是 ArkUI 中专为轮播图、引导页、图片画廊等场景设计的滑动容器。它内置指示器、自动播放、循环滑动等能力配合SwiperController可以实现编程式翻页。本文通过完整示例演示 Swiper 的核心特性。运行效果初始状态Banner 轮播滑动至第二页核心 API 一览API说明Swiper(controller?)轮播容器子组件逐页显示.loop(bool)是否循环播放默认 true.autoPlay(bool)是否自动播放.interval(ms)自动播放间隔毫秒.indicator(bool/DotIndicator/DigitIndicator)指示器样式.index(n)当前页索引.duration(ms)翻页动画时长.curve(Curve)翻页动画曲线.onChange(idx)页面切换回调.itemSpace(n)相邻页的间距用于“卡片流“效果controller.showNext()编程式切换到下一页controller.showPrevious()编程式切换到上一页完整示例代码interface BannerItem { title: string subtitle: string bg: string icon: string } interface CardItem { name: string desc: string color: string } Entry Component struct Index { State currentBanner: number 0 State currentCard: number 0 State autoPlay: boolean true private bannerController: SwiperController new SwiperController() private cardController: SwiperController new SwiperController() private banners: BannerItem[] [ { title: HarmonyOS 6.1, subtitle: 全新 ArkUI 组件体系正式上线, bg: #0044cc, icon: }, { title: 折叠屏适配, subtitle: 一套代码完美适配多种屏幕形态, bg: #cc3300, icon: }, { title: 性能优化, subtitle: Swiper 流畅帧率提升 40%, bg: #006633, icon: ⚡ }, { title: 开发者工具, subtitle: DevEco Studio 全面升级, bg: #6600aa, icon: }, ] private cards: CardItem[] [ { name: 组件库, desc: 200 内置 UI 组件, color: #e8f0ff }, { name: 动画引擎, desc: 60fps 流畅动效, color: #fff0e8 }, { name: 跨平台, desc: 一次开发多端运行, color: #e8fff0 }, { name: 状态管理, desc: MVVM 响应式架构, color: #f8e8ff }, ] build() { Scroll() { Column({ space: 20 }) { Text(Swiper 轮播 页面滑动) .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor(#1a1a1a) .width(100%) .padding({ left: 16, top: 16 }) // ── 1. 全屏 Banner 轮播 ── Column({ space: 10 }) { Text(① 全屏 Banner自动轮播) .fontSize(15) .fontWeight(FontWeight.Bold) .fontColor(#333) .padding({ left: 16 }) Swiper(this.bannerController) { ForEach(this.banners, (item: BannerItem) { Column({ space: 8 }) { Text(item.icon).fontSize(48) Text(item.title) .fontSize(22) .fontWeight(FontWeight.Bold) .fontColor(#ffffff) Text(item.subtitle) .fontSize(13) .fontColor(rgba(255,255,255,0.85)) .textAlign(TextAlign.Center) .padding({ left: 24, right: 24 }) } .width(100%) .height(180) .backgroundColor(item.bg) .justifyContent(FlexAlign.Center) .borderRadius(12) }) } .loop(true) .autoPlay(this.autoPlay) .interval(2500) .duration(400) .curve(Curve.EaseOut) .indicator( new DotIndicator() .itemWidth(6) .itemHeight(6) .selectedItemWidth(20) .selectedItemHeight(6) .color(#88bbff) .selectedColor(#ffffff) ) .onChange((idx: number) { this.currentBanner idx }) .margin({ left: 16, right: 16 }) // 控制按钮 Row({ space: 10 }) { Button(上一张) .height(36) .fontSize(13) .backgroundColor(#0066ff) .onClick(() { this.bannerController.showPrevious() }) Text(第 (this.currentBanner 1).toString() / this.banners.length.toString() 张) .fontSize(13) .fontColor(#888) .layoutWeight(1) .textAlign(TextAlign.Center) Button(下一张) .height(36) .fontSize(13) .backgroundColor(#0066ff) .onClick(() { this.bannerController.showNext() }) Button(this.autoPlay ? 停止 : 自动) .height(36) .fontSize(13) .backgroundColor(this.autoPlay ? #ff6600 : #00aa44) .onClick(() { this.autoPlay !this.autoPlay }) } .width(100%) .padding({ left: 16, right: 16 }) } .width(100%) // ── 2. 卡片流itemSpace displayCount── Column({ space: 10 }) { Text(② 卡片流部分预览相邻页) .fontSize(15) .fontWeight(FontWeight.Bold) .fontColor(#333) .padding({ left: 16 }) Swiper(this.cardController) { ForEach(this.cards, (card: CardItem) { Column({ space: 8 }) { Text(card.name) .fontSize(18) .fontWeight(FontWeight.Bold) .fontColor(#333) Text(card.desc) .fontSize(13) .fontColor(#888) } .width(100%) .height(100) .backgroundColor(card.color) .borderRadius(14) .justifyContent(FlexAlign.Center) .border({ width: 1, color: #e0e0e0 }) }) } .loop(false) .autoPlay(false) .itemSpace(12) .indicator(false) .curve(Curve.Smooth) .onChange((idx: number) { this.currentCard idx }) .margin({ left: 32, right: 32 }) Row({ space: 4 }) { ForEach(this.cards, (_c: CardItem, idx: number) { Column() .width(this.currentCard idx ? 20 : 6) .height(6) .backgroundColor(this.currentCard idx ? #0066ff : #d0d0d0) .borderRadius(3) }) } .justifyContent(FlexAlign.Center) } .width(100%) // ── 3. 数字指示器 ── Column({ space: 10 }) { Text(③ 数字指示器DigitIndicator) .fontSize(15) .fontWeight(FontWeight.Bold) .fontColor(#333) .padding({ left: 16 }) Swiper() { ForEach([#ff6b6b, #feca57, #48dbfb, #1dd1a1], (color: string) { Column() .width(100%) .height(100) .backgroundColor(color) .borderRadius(12) }) } .loop(true) .autoPlay(true) .interval(1800) .indicator( new DigitIndicator() .fontColor(#ffffff) .selectedFontColor(#ffffff) .digitFont({ size: 14, weight: FontWeight.Bold }) ) .margin({ left: 16, right: 16 }) } .width(100%) Column().height(20) } .width(100%) } .width(100%) .height(100%) .backgroundColor(#ffffff) } }关键知识点1. 指示器Indicator三种形式// 布尔值显示/隐藏默认圆点 .indicator(true) .indicator(false) // DotIndicator自定义圆点样式 .indicator( new DotIndicator() .itemWidth(6).itemHeight(6) .selectedItemWidth(20).selectedItemHeight(6) // 选中时拉长为胶囊 .color(#cccccc) .selectedColor(#0066ff) ) // DigitIndicator数字形式 1 / 4 .indicator( new DigitIndicator() .fontColor(#ffffff) .selectedFontColor(#ffffff) )2. 卡片流效果通过.itemSpace(n)设置相邻卡片间距并给 Swiper 左右各留 margin大于间距就能看到相邻卡片的“预览“效果Swiper() .itemSpace(12) // 相邻卡片间距 .indicator(false) // 通常卡片流不需要指示器 .margin({ left: 32, right: 32 }) // 留出边距让相邻卡片露出3. SwiperController 编程式控制private controller: SwiperController new SwiperController() Swiper(this.controller) { ... } // 翻页 this.controller.showNext() this.controller.showPrevious()4. 动画曲线Curve值效果适合场景Curve.Linear匀速少用Curve.EaseOut减速结束Banner 轮播Curve.Smooth平滑过渡卡片翻页Curve.FastOutSlowInMaterial 风格通用5. onChange 与 index 的关系.onChange(idx)在每次翻页完成时触发idx是目标页的索引从 0 开始。若需要初始化时指定展示页用.index(n)属性Swiper() .index(2) // 从第 3 页下标 2开始显示 .onChange((idx: number) { this.currentPage idx })小结Swiper专为页面级滑动和轮播设计内置指示器、自动播放、循环滑动DotIndicator支持选中态拉伸为胶囊形视觉上更优雅SwiperController提供showNext/showPrevious用于外部按钮控制itemSpace margin组合实现卡片流“露出相邻页“的效果注意区分loop逻辑循环和autoPlay interval自动翻页是独立配置项