HarmonyOS应用开发实战 | ArkTS Swiper轮播组件使用指南
💫 坚果派·红目香薰 倾情分享
🎯 用心打造每一个技术细节,为开发者创造更多价值
📱 让HarmonyOS开发变得更简单、更有趣
✨ 写在前面的话
嗨,亲爱的技术朋友们!👋
我是来自坚果派的红目香薰,一个热爱技术、专注HarmonyOS开发的程序媛。在这个数字化飞速发展的时代,HarmonyOS作为华为自主研发的操作系统,正在改变着我们的数字生活体验。
🌈 为什么要写这个系列?
-
💡 让复杂的技术变得简单易懂
-
🚀 帮助更多开发者快速上手HarmonyOS
-
💝 分享实战经验,避免踩坑
-
🌟 用代码创造美好,用技术传递温暖
每一个Demo都是我精心设计和反复测试的结果,希望能够为你的HarmonyOS开发之路点亮一盏明灯。✨
今天我们来深入学习HarmonyOS中最受欢迎的展示组件之一——Swiper轮播组件。从基础轮播到炫酷特效,让我们一起打造令人惊艳的轮播体验!
📋 Demo功能说明
🎯 核心功能
本Demo展示了HarmonyOS中Swiper组件的全面使用方法,包括:
-
🖼️ 基础图片轮播展示
-
🎨 自定义指示器样式
-
🔄 自动播放和循环轮播
-
💫 多种切换动画效果
-
📱 垂直和水平轮播方向
-
🎯 轮播事件监听和处理
-
✨ 3D效果和视差滚动
-
🌟 卡片式轮播布局
✨ 特色亮点
-
🎨 视觉精美:多种轮播样式和动画效果
-
🚀 性能优化:流畅的滑动体验和内存管理
-
📱 响应式设计:适配不同屏幕尺寸和方向
-
💡 交互丰富:支持手势操作和程序控制
-
🌟 效果炫酷:3D变换和视觉特效
🎨 界面展示
界面采用多样化的轮播展示:
-
经典轮播:传统的图片轮播效果
-
卡片轮播:卡片式布局的轮播
-
3D轮播:立体视觉效果的轮播
-
垂直轮播:上下滑动的轮播方式
-
自定义轮播:个性化指示器和控制
📱 适用场景
-
🛍️ 电商应用的商品展示轮播
-
📰 新闻应用的头条轮播
-
🏠 首页的广告横幅轮播
-
📱 应用引导页的功能介绍
-
🎮 游戏应用的截图展示
-
🏨 旅游应用的景点图片轮播
🔧 核心代码说明
📁 项目结构
SwiperDemo/
├── src/
│ ├── main/
│ │ ├── ets/
│ │ │ ├── pages/
│ │ │ │ └── Index.ets // 主页面
│ │ │ └── entryability/
│ │ └── resources/
│ │ ├── base/
│ │ │ ├── element/
│ │ │ └── media/
│ │ │ ├── pic1.jpg // 轮播图片1
│ │ │ ├── pic2.jpg // 轮播图片2
│ │ │ ├── pic3.jpg // 轮播图片3
│ │ │ └── pic4.jpg // 轮播图片4
│ │ └── rawfile/
│ └── module.json5
🎯 关键技术点
1. Swiper组件基础结构
@Entry
@Component
struct Index {
@State currentIndex: number = 0
@State isAutoPlay: boolean = true
@State selectedTab: number = 0
// 轮播图片数据
private imageList: Resource[] = [
$r('app.media.pic1'),
$r('app.media.pic2'),
$r('app.media.pic3'),
$r('app.media.pic4')
]
// 轮播内容数据
private swiperData: SwiperDataItem[] = [
{
title: '🌅 美丽日出',
subtitle: '迎接新的一天',
description: '清晨的第一缕阳光,带来希望与温暖',
color: '#FF6B6B'
},
{
title: '🌊 碧海蓝天',
subtitle: '无限的自由',
description: '广阔的海洋,让心灵得到释放',
color: '#4ECDC4'
},
{
title: '🏔️ 雄伟山峰',
subtitle: '征服的勇气',
description: '高山之巅,体验征服自然的成就感',
color: '#45B7D1'
},
{
title: '🌸 樱花盛开',
subtitle: '浪漫的季节',
description: '粉色花海,感受春天的浪漫气息',
color: '#F7DC6F'
}
]
build() {
Column() {
// 标题区域
this.buildTitleSection()
// 标签页
this.buildTabSection()
// 内容区域
if (this.selectedTab === 0) {
this.buildBasicSwiper()
} else if (this.selectedTab === 1) {
this.buildCardSwiper()
} else if (this.selectedTab === 2) {
this.buildVerticalSwiper()
} else {
this.buildCustomSwiper()
}
// 控制面板
this.buildControlPanel()
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
// 标题区域
@Builder
buildTitleSection() {
Column({ space: 10 }) {
Text('🎠 HarmonyOS Swiper轮播组件')
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
.width('100%')
.padding(20)
.borderRadius(15)
.linearGradient({
angle: 45,
colors: [['#667eea', 0.0], ['#764ba2', 1.0]]
})
.shadow({
radius: 10,
color: '#40000000',
offsetX: 0,
offsetY: 5
})
Text('打造令人惊艳的轮播体验')
.fontSize(14)
.fontColor('#666666')
.textAlign(TextAlign.Center)
.fontStyle(FontStyle.Italic)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.margin({ bottom: 10 })
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
// 标签页
@Builder
buildTabSection() {
Row({ space: 5 }) {
Button('基础轮播')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 0 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 0 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 0
})
Button('卡片轮播')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 1 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 1 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 1
})
Button('垂直轮播')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 2 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 2 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 2
})
Button('自定义')
.width(70)
.height(35)
.fontSize(12)
.backgroundColor(this.selectedTab === 3 ? '#3498DB' : '#ECF0F1')
.fontColor(this.selectedTab === 3 ? Color.White : '#7F8C8D')
.borderRadius(8)
.onClick(() => {
this.selectedTab = 3
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.padding({ left: 20, right: 20, bottom: 10 })
}
// 基础轮播
@Builder
buildBasicSwiper() {
Column({ space: 20 }) {
// 经典轮播
Column({ space: 10 }) {
Text('🖼️ 经典图片轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.imageList, (item: Resource, index: number) => {
Stack({ alignContent: Alignment.BottomStart }) {
Image(item)
.width('100%')
.height(200)
.borderRadius(12)
.objectFit(ImageFit.Cover)
// 图片信息覆盖层
Column({ space: 5 }) {
Text(this.swiperData[index].title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text(this.swiperData[index].subtitle)
.fontSize(14)
.fontColor('#E0E0E0')
}
.alignItems(HorizontalAlign.Start)
.padding(20)
.width('100%')
.linearGradient({
angle: 180,
colors: [['#00000000', 0.0], ['#80000000', 1.0]]
})
.borderRadius({ bottomLeft: 12, bottomRight: 12 })
}
})
}
.width('100%')
.height(200)
.autoPlay(this.isAutoPlay)
.interval(3000)
.loop(true)
.duration(500)
.curve(Curve.EaseInOut)
.indicator(
Indicator.dot()
.itemWidth(8)
.itemHeight(8)
.selectedItemWidth(20)
.selectedItemHeight(8)
.color('#80FFFFFF')
.selectedColor('#FFFFFF')
)
.onChange((index: number) => {
this.currentIndex = index
})
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
// 缩略图轮播
Column({ space: 10 }) {
Text('🔍 缩略图轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.imageList, (item: Resource) => {
Image(item)
.width('100%')
.height(150)
.borderRadius(8)
.objectFit(ImageFit.Cover)
})
}
.width('100%')
.height(150)
.autoPlay(false)
.loop(true)
.indicator(
Indicator.digit()
.fontColor(Color.White)
.selectedFontColor('#007DFF')
.digitFont({ size: 14, weight: FontWeight.Bold })
.selectedDigitFont({ size: 16, weight: FontWeight.Bold })
)
.displayArrow({
showBackground: true,
isSidebarMiddle: true,
backgroundSize: 24,
backgroundColor: '#80000000',
arrowSize: 12,
arrowColor: Color.White
}, false)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 卡片轮播
@Builder
buildCardSwiper() {
Column({ space: 20 }) {
// 3D卡片轮播
Column({ space: 10 }) {
Text('🎴 3D卡片轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.swiperData, (item:SwiperDataItem, index: number) => {
Column({ space: 15 }) {
Image(this.imageList[index])
.width('100%')
.height(120)
.borderRadius(12)
.objectFit(ImageFit.Cover)
Column({ space: 8 }) {
Text(item.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Text(item.subtitle)
.fontSize(16)
.fontColor(item.color)
.fontWeight(FontWeight.Medium)
Text(item.description)
.fontSize(14)
.fontColor('#666666')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Row({ space: 10 }) {
Button('了解更多')
.height(32)
.fontSize(12)
.backgroundColor(item.color)
.borderRadius(16)
Button('收藏')
.height(32)
.fontSize(12)
.backgroundColor(Color.Transparent)
.fontColor(item.color)
.border({ width: 1, color: item.color })
.borderRadius(16)
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.alignItems(HorizontalAlign.Start)
.padding({ left: 15, right: 15, bottom: 15 })
}
.width('90%')
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({
radius: 15,
color: '#30000000',
offsetX: 0,
offsetY: 8
})
})
}
.width('100%')
.height(280)
.autoPlay(this.isAutoPlay)
.interval(4000)
.loop(true)
.displayCount(1, true)
.indicator(
Indicator.dot()
.itemWidth(10)
.itemHeight(10)
.selectedItemWidth(10)
.selectedItemHeight(10)
.color('#C0C0C0')
.selectedColor('#007DFF')
)
}
.width('100%')
.backgroundColor('#F8F9FA')
.padding(20)
.borderRadius(12)
// 多卡片展示
Column({ space: 10 }) {
Text('📚 多卡片展示')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.imageList, (item: Resource, index: number) => {
Column({ space: 10 }) {
Image(item)
.width('100%')
.height(100)
.borderRadius(8)
.objectFit(ImageFit.Cover)
Text(this.swiperData[index].title)
.fontSize(14)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
.textAlign(TextAlign.Center)
}
.width('100%')
.backgroundColor(Color.White)
.padding(10)
.borderRadius(10)
.shadow({
radius: 5,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
})
}
.width('100%')
.height(140)
.autoPlay(false)
.loop(true)
.displayCount(2.5, true)
.itemSpace(10)
.indicator(false)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 垂直轮播
@Builder
buildVerticalSwiper() {
Column({ space: 20 }) {
// 垂直图片轮播
Column({ space: 10 }) {
Text('📱 垂直图片轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.imageList, (item: Resource, index: number) => {
Stack({ alignContent: Alignment.Center }) {
Image(item)
.width('100%')
.height('100%')
.borderRadius(12)
.objectFit(ImageFit.Cover)
Column({ space: 10 }) {
Text(this.swiperData[index].title)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.textShadow({
radius: 5,
color: '#80000000',
offsetX: 2,
offsetY: 2
})
Text(this.swiperData[index].description)
.fontSize(16)
.fontColor('#E0E0E0')
.textAlign(TextAlign.Center)
.maxLines(2)
.textShadow({
radius: 3,
color: '#80000000',
offsetX: 1,
offsetY: 1
})
}
.padding(20)
}
})
}
.width('100%')
.height(250)
.vertical(true)
.autoPlay(this.isAutoPlay)
.interval(3500)
.loop(true)
.indicator(
Indicator.dot()
.itemWidth(8)
.itemHeight(8)
.selectedItemWidth(8)
.selectedItemHeight(20)
.color('#80FFFFFF')
.selectedColor('#FFFFFF')
.right(20)
)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
// 垂直文字轮播
Column({ space: 10 }) {
Text('📰 垂直文字轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Swiper() {
ForEach(this.swiperData, (item:SwiperDataItem, index: number) => {
Row({ space: 15 }) {
Text('📢')
.fontSize(20)
.width(40)
.textAlign(TextAlign.Center)
Column({ space: 5 }) {
Text(item.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Text(item.description)
.fontSize(14)
.fontColor('#666666')
.maxLines(1)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Text('>')
.fontSize(16)
.fontColor('#C0C0C0')
}
.width('100%')
.padding({ left: 15, right: 15, top: 10, bottom: 10 })
.backgroundColor('#F8F9FA')
.borderRadius(8)
})
}
.width('100%')
.height(80)
.vertical(true)
.autoPlay(true)
.interval(2000)
.loop(true)
.indicator(false)
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 自定义轮播
@Builder
buildCustomSwiper() {
Column({ space: 20 }) {
// 自定义指示器轮播
Column({ space: 15 }) {
Text('🎨 自定义指示器')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Stack({ alignContent: Alignment.Bottom }) {
Swiper() {
ForEach(this.imageList, (item: Resource, index: number) => {
Image(item)
.width('100%')
.height(180)
.borderRadius(12)
.objectFit(ImageFit.Cover)
})
}
.width('100%')
.height(180)
.autoPlay(this.isAutoPlay)
.interval(3000)
.loop(true)
.indicator(false)
.onChange((index: number) => {
this.currentIndex = index
})
// 自定义指示器
Row({ space: 8 }) {
ForEach(this.imageList, (item: Resource, index: number) => {
Text(this.swiperData[index].title.split(' ')[0])
.fontSize(12)
.fontColor(this.currentIndex === index ? '#007DFF' : '#FFFFFF')
.fontWeight(this.currentIndex === index ? FontWeight.Bold : FontWeight.Normal)
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.backgroundColor(this.currentIndex === index ? '#FFFFFF' : '#80000000')
.borderRadius(12)
.onClick(() => {
// 这里可以添加点击切换逻辑
})
})
}
.margin({ bottom: 15 })
}
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
// 进度条轮播
Column({ space: 15 }) {
Text('📊 进度条轮播')
.fontSize(18)
.fontWeight(FontWeight.Medium)
.fontColor('#333333')
Column({ space: 10 }) {
Swiper() {
ForEach(this.swiperData, (item:SwiperDataItem, index: number) => {
Column({ space: 15 }) {
Image(this.imageList[index])
.width('100%')
.height(120)
.borderRadius(8)
.objectFit(ImageFit.Cover)
Text(item.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
Text(item.description)
.fontSize(14)
.fontColor('#666666')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.alignItems(HorizontalAlign.Start)
.padding(15)
})
}
.width('100%')
.height(200)
.autoPlay(this.isAutoPlay)
.interval(4000)
.loop(true)
.indicator(false)
.onChange((index: number) => {
this.currentIndex = index
})
// 自定义进度条
Row({ space: 5 }) {
ForEach(this.imageList, (item: Resource, index: number) => {
Progress({
value: this.currentIndex === index ? 100 : 0,
total: 100,
type: ProgressType.Linear
})
.width(60)
.height(3)
.color('#007DFF')
.backgroundColor('#E0E0E0')
})
}
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
.width('100%')
.backgroundColor(Color.White)
.padding(20)
.borderRadius(12)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: 2
})
}
.layoutWeight(1)
.padding({ left: 20, right: 20 })
}
// 控制面板
@Builder
buildControlPanel() {
Row({ space: 15 }) {
Text(`当前页面: ${this.currentIndex + 1}/${this.imageList.length}`)
.fontSize(14)
.fontColor('#666666')
.layoutWeight(1)
Button(this.isAutoPlay ? '⏸️ 暂停' : '▶️ 播放')
.height(35)
.fontSize(12)
.backgroundColor(this.isAutoPlay ? '#E74C3C' : '#27AE60')
.borderRadius(18)
.onClick(() => {
this.isAutoPlay = !this.isAutoPlay
})
}
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.shadow({
radius: 8,
color: '#20000000',
offsetX: 0,
offsetY: -2
})
}
}
interface SwiperDataItem {
title: string
subtitle: string
description: string
color: string
}
⚙️ 配置文件
// module.json5 配置
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background"
}
]
}
}
🚀 运行效果
📱 界面展示
运行后的界面将展示:
-
🎠 渐变色标题,展示Swiper组件主题
-
🏷️ 四个标签页:基础轮播、卡片轮播、垂直轮播、自定义
-
🖼️ 基础轮播:经典图片轮播和缩略图轮播
-
🎴 卡片轮播:3D卡片效果和多卡片展示
-
📱 垂直轮播:上下滑动的图片和文字轮播
-
🎨 自定义轮播:个性化指示器和进度条轮播
-
🎛️ 控制面板:显示当前页面和播放控制
✅ 功能验证
-
基础功能:切换标签页,查看不同类型轮播
-
自动播放:观察轮播的自动切换效果
-
手势操作:左右滑动切换轮播页面
-
指示器:查看不同样式的指示器效果
-
播放控制:点击播放/暂停按钮控制自动播放
-
页面监听:观察当前页面数字的实时更新
💡 开发小贴士
🎯 最佳实践
-
💫 性能优化:合理设置autoPlay间隔时间,避免过于频繁切换
-
🎨 视觉设计:使用合适的指示器样式,提升用户体验
-
⚡ 内存管理:大量图片时考虑懒加载和图片压缩
-
🔧 响应式设计:根据屏幕尺寸调整轮播尺寸和显示数量
🚨 常见问题
-
图片加载失败:确保图片资源正确放置在media目录下
-
轮播卡顿:检查图片大小,考虑压缩或优化图片格式
-
指示器位置异常:注意Stack布局和alignContent属性设置
-
自动播放不生效:检查autoPlay属性和interval设置
📚 扩展学习
-
自定义动画:学习如何创建自定义的轮播切换动画
-
懒加载优化:实现图片的按需加载机制
-
手势识别:添加更丰富的手势操作支持
🎉 总结与展望
通过这个Demo,我们学习了:
-
✨ Swiper组件的基础使用和高级特性
-
🎯 不同类型轮播的设计和实现方法
-
💡 自定义指示器和控制器的开发技巧
-
🎨 创建美观轮播界面的设计原则
Swiper组件作为现代移动应用中最重要的展示组件之一,掌握其各种用法对于创建吸引人的用户界面至关重要。从简单的图片轮播到复杂的3D效果,每一个细节都体现着应用的品质和用户体验。
希望这个示例能够帮助到正在学习HarmonyOS开发的你!下一期我们将探索更多有趣的UI组件,敬请期待!如果你有任何问题或建议,欢迎在评论区留言交流。
🔗 相关资源
-
💬 坚果派技术社区
🌟 如果这篇文章对你有帮助,请点赞支持!🌟
让我们一起在HarmonyOS的世界里创造更多可能!
© 2025 坚果派·红目香薰 | 用心分享,用技术创造价值
更多推荐
所有评论(0)