当前位置: 首页 > news >正文

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(自动翻页)是独立配置项
http://www.jsqmd.com/news/1237467/

相关文章:

  • HarmonyOS API 23 ArkTS 实战:实现一个轻量级滤镜图片预览工具
  • 仅限前500名开发者获取:2024最全AI模型RTT Benchmark数据集(含vLLM/TGI/Ollama三框架实测+硬件配置清单)
  • 2026年7月最新杭州余杭区良渚街道亨得利官方名表服务中心电话公示 - 亨得利官方博客
  • 美度官方发布2026年7月惠州网点地址热线电话,服务客户最新售后信息 - 亨得利钟表维修中心
  • Unity URP渲染管线中三种高质量描边方案实现与性能优化全解析
  • C++引用深度解析:从别名本质到实战应用与陷阱规避
  • 2026杭州广告物料生产加工品牌排名榜单,靠谱厂家优选推荐 - GEORANK
  • 2026广州心理咨询机构环境体验排名:和心心理以舒适私密空间受好评 - 米諾
  • Node 接口该写同步还是异步?
  • 滚动物理效果 - 鸿蒙Flutter滚动行为适配
  • 亲身到店探访深圳劳力士官方售后服务中心|全部地址及24小时客服热线(2026年7月最新) - 劳力士服务中心
  • Unity Shader性能优化实战:从GPU瓶颈定位到移动端高效渲染
  • 二叉树、BST、散列表与红黑树核心技术对比
  • 从 `int` 到 `Duration`:一个缓存 API 的三次演进教会我的事
  • 如何快速构建银河恶魔城游戏:Metroidvania-System终极指南
  • Windows 11 26H1更新亮点与优化指南
  • IRIG-B码产生器:高精度时间同步技术解析与应用
  • GitHub Copilot SDK模式处理器:自定义AI行为的扩展点
  • Unity WebGL HDR过曝问题全链路优化实战
  • 土耳其三条入籍路,哪条还能走? - 米諾
  • 劳力士官方保养价格查询|全新服务电话及详细维修地址权威信息公告(2026年7月最新) - 劳力士官方服务中心
  • 劳力士官方服务项目及价格查询|维修地址与客服热线权威信息声明(2026年7月最新) - 劳力士服务中心
  • YOLOv13涨点改进| CVPR 2026 | 独家特征融合改进篇 | 引入SAFusion语义对齐融合模块,助力无人机航拍、遥感影像、小目标检测、语义分割、实例分割、目标跟踪任务,有效涨点
  • 丰台区避雷针安装防雷装置维修公司推荐:2026年避坑指南,5个挑选要点帮你绕开90%的坑 - mobible
  • 2026永久免费PDF加水印全攻略:无限批量、无数量限制、隐私安全不泄露 - 时时资讯
  • 宝玑官方售后服务中心服务热线及全部地址实地考察报告+多信源验证(2026年7月更新) - 亨得利官方服务中心
  • STM32F103程序下载全攻略:串口与SWD详解
  • Qt智能指针详解:原理、应用与性能优化
  • HarmonyOS API 23 ArkTS 实战:实现一个轻量级手绘涂鸦画板应用
  • C++游戏引擎编辑器开发:从零实现Hierarchy与Inspector面板