📚鸿蒙开发往期学习笔录✒️:
✒️ 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
✒️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
✒️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
✒️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
✒️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
✒️ 记录一场鸿蒙开发岗位面试经历~
✒️ 持续更新中……
概述
图文作品播放是一种常见的功能,它的特点是:由多张图片组成一个合集,图片可以自动进行轮播,也可以手动去进行图片切换。自动轮播时,图片下方的进度条缓慢加载至完成状态;手动切换时,图片下方的进度条瞬间切换至已完成状态或未完成状态。
由于原生Swiper组件自带的导航点指示器目前只支持数字和圆点的样式,不支持对应的特殊样式,因此需要通过自定义指示器(即进度条)来模拟底部的导航条效果。
本文中将通过场景介绍、技术选型和实现方案三个部分来进行介绍。
场景介绍
常见的图文作品,可以自动循环播放和手动切换播放合集中的图片。
- 当作品自动播放时,图片每过几秒会自动切换到下一张,且下方进度条进度与该图片的停留时间匹配。
- 当作品手动播放时,下方进度条会跟着图片的滑动切换而改变成未完成状态或已完成状态。
技术选型
从技术角度看,图文作品轮播效果可通过Swiper组件和它的指示器的联动效果实现,由于Swiper组件的指示器无法自定义,所以需要拆开实现:
- 上面图片的轮播部分继续使用Swiper组件实现。
- 下面的指示器,由于Swiper组件只有两种显示模式,一个是圆点,一个是数字,很明显是不能实现进度条的效果。所以需要关闭原生指示器,自定义一个指示器。
示意效果如下图所示。
实现方案
图片区域实现
图片区域需要使用 Swiper 组件来实现。将图片合集的数据传入Swiper组件后,需要对Swiper组件设置一些属性,来完成图片自动轮播效果:
- 通过设置 loop 属性控制是否循环播放,该属性默认值为true。当loop为true时,在显示第一页或最后一页时,可以继续往前切换到前一页或者往后切换到后一页。如果loop为false,则在第一页或最后一页时,无法继续向前或者向后切换页面。
- 通过设置 autoPlay 属性,控制是否自动轮播子组件。该属性默认值为false。autoPlay为true时,会自动切换播放子组件。
- 通过设置 interval 属性,控制子组件与子组件之间的播放间隔。interval属性默认值为3000,单位毫秒。
- 通过设置 indicator 属性为false,来关闭Swiper组件自带的导航点指示器样式
Swiper(this.swiperController) {
LazyForEach(this.data, (item: PhotoData, index: number) => {
Image($r(`app.media.` + item.id))
.width(this.foldStatus === 2 ? '100%' : '70%')
.height('100%')
}, (item: PhotoData) => JSON.stringify(item))
}
.loop(!this.slide ? true : false)
.autoPlay(!this.slide ? true : false)
.interval(3000)
.indicator(false)
示意效果如下图所示。
底部导航点设计
底部导航点(进度条)有三种样式:未完成状态的样式、已完成状态的样式和正在进行进度增长的样式。
- 开发者可以使用 层叠布局 (Stack) ,配合Row容器来实现进度条的布局。
- 要实现进度条缓慢增长至完成状态且用时与图片播放时间相匹配的效果,可以给Row容器组件添加 属性动画 (animation) ,设置duration(动画持续时间)与图片播放时间匹配即可。
- 进度条状态切换:通过播放图片的currentIndex与进度条的index进行比较,当currentIndex大于或等于index时,需要将进度条样式设置成已完成状态,否则是未完成状态。可以通过设置完成时进度条的背景颜色为Color.White或Color.Grey来实现两种样式的进度条切换。
创建自定义组件progressComponent。
@Builder
progressComponent() {
Row({ space: 5 }) {
ForEach(this.progressData, (item: PhotoData, index: number) => {
Stack({ alignContent: Alignment.Start }) {
Row()
.zIndex(1)
.width(this.currentIndex >= index && !this.slide ? '100%' : '0')
.height(2)
.borderRadius(2)
.backgroundColor(Color.White)
.animation(!this.slide ? {
duration: this.duration - 400,
curve: Curve.Linear,
iterations: 1,
playMode: PlayMode.Normal,
onFinish: () => {
if (this.currentIndex === this.progressData.length - 1) {
this.duration = 400;
this.currentIndex = -1;
}
}
} : { duration: 0, iterations: 1 })
}
.width('100%')
.height(2)
.borderRadius(2)
.backgroundColor(this.currentIndex >= index && this.slide ? Color.White : Color.Grey)
.layoutWeight(1)
}, (item: PhotoData) => JSON.stringify(item))
}
.width('100%')
.height(50)
}
示意效果如下图所示。
上述代码中,this.progressData为图片集合的数组,this.currentIndex为当前播放的图片在图片集合数组中的索引,index为进度条对应的图片在图片集合数组中的索引。当this.currentIndex >= index时,表示图片集合数组中索引0-index的进度条都是已完成状态。
当图片集合手动播放时,随着图片的切换,下方进度条会跟随着切换为已完成状态或未完成状态。此时,开发者需要给Swiper组件添加onGestureSwipe 事件,来判断页面是否跟手滑动。
Swiper(this.swiperController) {
// ...
}
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
this.slide = true;
})
slide为布尔值,用来判断页面是否跟手滑动。默认值为false,当页面跟手滑动时,slide的值为true。
上述内容介绍了如何实现图文作品中自动播放和手动播放的功能,其中包括场景介绍、技术选型和代码实现等。由于Swiper组件的指示器只有两种显示模式,且不支持自定义样式。所以,开发者需要通过自定义Swiper指示器,来实现进度条切换效果。