本文介绍一下轮播组件Swiper的基本使用,各属性的含义已在代码中注释说明,可以通过动态修改,查看各属性起到的作用。
通过一个Row容器组件添加属性动画,设置动画持续时间与swiper播放时间匹配,实现一个带进度的指示器,如图。
看一下效果图:
演示.gif
源码:
@Entry
@ComponentV2
struct SwiperTest{
private swiperController: SwiperController = new SwiperController();
datas:string[]=['0','1','2','3','4','5','6'];
@Local autoPlay:boolean = true//是否自动播放
@Local loop:boolean = true//是否开启循环
@Local interval:number=4000 //自动播放时播放的时间间隔
@Local duration:number=1000 //子组件切换的动画时长
@Local itemSpace:number=5 //子组件与子组件之间间隙
@Local displayCount:number=1 //视窗内元素显示个数
@Local nextMargin:number=35 //设置后边距,用于露出后一项的一小部分
@Local prevMargin:number=35 //设置前边距,用于露出前一项的一小部分
@Local showBackground:boolean=true //箭头底板是否显示
@Local isSidebarMiddle:boolean=true //箭头显示位置
@Local displayArrow:boolean=true //箭头显示
@Local indicator:IndicatorComponentController | DotIndicator | DigitIndicator | boolean=
new DotIndicator()
.itemWidth(15)
.itemHeight(15)
.selectedItemWidth(15)
.selectedItemHeight(15)
.color(Color.Gray)
.selectedColor(Color.Blue) //组件控制器
@Local slide: boolean = false; //判断页面是否跟手滑动
@Local currentIndex: number=0
@Local changeDuration: number=this.interval
build() {
Column({space:10}){
Swiper(this.swiperController){
ForEach(this.datas,(item: string, index:number)=>{
Text(item.toString())
.width('100%')
.height(160)
.backgroundColor(getRandomColor())
.textAlign(TextAlign.Center)
.fontSize(30)
})
}
.index(this.currentIndex) //当前在容器中显示的子组件的索引值
.autoPlay(this.autoPlay) //是否自动播放
.interval(this.interval) //自动播放时播放的时间间隔
.indicator(this.indicator)// 设置圆点导航点样式
.loop(this.loop)//是否开启循环
.duration(this.duration) //子组件切换的动画时长
.vertical(false) //是否为纵向滑动
.itemSpace(this.itemSpace) //子组件与子组件之间间隙
.displayMode(SwiperDisplayMode.STRETCH) //主轴方向上元素排列的模式
.cachedCount(2) //预加载子组件个数
.disableSwipe(false) //禁用组件滑动切换功能
.curve(Curve.Linear) //动画曲线
.displayCount(this.displayCount) //视窗内元素显示个数
.effectMode(EdgeEffect.Spring) //边缘滑动效果
.displayArrow(this.displayArrow?{ // 设置导航点箭头样式
showBackground: this.showBackground, //设置箭头底板是否显示
isSidebarMiddle: this.isSidebarMiddle, //设置箭头显示位置 true时箭头居中显示在swiper组件两侧,为false时显示在导航点指示器两侧
backgroundSize: 24, //设置底板大小
backgroundColor: Color.White, //设置底板颜色
arrowSize: 18, //设置箭头大小
arrowColor: Color.Blue //设置箭头颜色
}:false , false)
.nextMargin(this.nextMargin) //设置后边距,用于露出后一项的一小部分
.prevMargin(this.prevMargin) //设置前边距,用于露出前一项的一小部分
.indicatorInteractive(true) //禁用组件导航点交互功能
.onAppear(()=>{
this.currentIndex=0
})
//当前显示的子组件索引变化时触发该事件,返回值为当前显示的子组件的索引值
.onChange((index: number) => {
this.currentIndex = index
this.changeDuration =this.interval
console.info(index.toString());
})
//在页面跟手滑动过程中 currentOffset Swiper当前显示元素在主轴方向上,相对于Swiper起始位置的位移
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
this.slide = true;
if (extraInfo.currentOffset > 200 && this.currentIndex > 0) {
this.currentIndex = index - 1;
}
console.info("index: " + index);
console.info("current offset: " + extraInfo.currentOffset);
})
//切换动画开始时触发该回调。参数为动画开始前的index值
.onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
console.info("index: " + index);
console.info("targetIndex: " + targetIndex);
console.info("current offset: " + extraInfo.currentOffset);
console.info("target offset: " + extraInfo.targetOffset);
console.info("velocity: " + extraInfo.velocity);
})
.onAnimationEnd((index: number, extraInfo: SwiperAnimationEvent) => {
console.info("index: " + index);
console.info("current offset: " + extraInfo.currentOffset);
})
Text('自定义进度条指示器')
this.progressComponent()
Row(){
Button('自动播放'+(this.autoPlay?'开':'关')).onClick(()=>{
this.autoPlay=!this.autoPlay
})
Column(){
Text("自动播放时间间隔")
Counter() {
Text(this.interval.toString())
}.width(120)
.onInc(() => {
this.interval+=1000;
})
.onDec(() => {
if (this.interval>0) {
this.interval-=1000;
}
})
}
Button('循环'+(this.loop?'开':'关')).onClick(()=>{
this.loop=!this.loop
})
}
Row(){
Button('圆点指示器').onClick(()=>{
this.indicator= new DotIndicator()
.itemWidth(8) //圆点导航指示器的宽
.itemHeight(8)
.selectedItemWidth(16) //选中Swiper组件圆点导航指示器的宽
.selectedItemHeight(8)
.color(Color.Gray)
.selectedColor(Color.Blue)
.maxDisplayCount(9)//导航点显示个数最大值
})
Button('数字指示器').onClick(()=>{
this.indicator=Indicator.digit() // 设置数字导航点样式
.top(200)
.fontColor(Color.Gray)
.selectedFontColor(Color.Gray)
.digitFont({ size: 20, weight: FontWeight.Bold })
.selectedDigitFont({ size: 20, weight: FontWeight.Normal })
})
Button('取消指示器').onClick(()=>{
this.indicator=false
})
}
Row(){
Column(){
Text("切换动画时长")
Counter() {
Text(this.duration.toString())
}.width(120)
.onInc(() => {
this.duration+=100;
})
.onDec(() => {
if (this.duration>0) {
this.duration-=100;
}
})
}
Column(){
Text("组件间隙")
Counter() {
Text(this.itemSpace.toString())
}.width(120)
.onInc(() => {
this.itemSpace+=1;
})
.onDec(() => {
if (this.itemSpace>0) {
this.itemSpace-=1;
}
})
}
}
Row(){
Column(){
Text("视窗内元素个数")
Counter() {
Text(this.displayCount.toString())
}
.onInc(() => {
this.displayCount+=1;
})
.onDec(() => {
if (this.displayCount>1) {
this.displayCount-=1;
}
})
}
Column(){
Text("前边距")
Counter() {
Text(this.prevMargin.toString())
}
.onInc(() => {
this.prevMargin+=1;
})
.onDec(() => {
if (this.prevMargin>0) {
this.prevMargin-=1;
}
})
}
Column(){
Text("后边距")
Counter() {
Text(this.nextMargin.toString())
}
.onInc(() => {
this.nextMargin+=1;
})
.onDec(() => {
if (this.nextMargin>0) {
this.nextMargin-=1;
}
})
}
}
Row(){
Button('箭头背景'+(this.showBackground?'显示':'隐藏')).onClick(()=>{
this.showBackground=!this.showBackground
})
Button('箭头'+(this.isSidebarMiddle?'swiper两侧':'指示器两侧')).onClick(()=>{
this.isSidebarMiddle=!this.isSidebarMiddle
})
Button('箭头'+(this.displayArrow?'显示':'隐藏')).onClick(()=>{
this.displayArrow=!this.displayArrow
})
}
}
}
//自定义进度条指示器
@Builder
progressComponent() {
Row({ space: 5 }) {
ForEach(this.datas, (item: string, index: number) => {
Stack({ alignContent: Alignment.Start }) {
Row()
.zIndex(0)
.width("100%")
.height(2)
.borderRadius(2)
.backgroundColor(Color.Grey)
Row()
.zIndex(1)
.width(this.currentIndex >= index && !this.slide ? '100%' : '0')
.height(2)
.borderRadius(2)
.backgroundColor(Color.White)
.animation(!this.slide ? {
duration: this.changeDuration,
curve: Curve.Linear,
iterations: 1,
playMode: PlayMode.Normal,
onFinish: () => {
if (this.currentIndex === this.datas.length - 1) {
this.changeDuration=0
this.currentIndex = -1;
}
}
} : { duration: 0, iterations: 1 })
Row()
.zIndex(2)
.width(this.currentIndex >= index && this.slide ?'100%':'0')
.height(2)
.borderRadius(2)
.backgroundColor(Color.White)
}
.width('100%')
.height(2)
.borderRadius(2)
.backgroundColor(this.currentIndex >= index && this.slide ? Color.White : Color.Grey)
.layoutWeight(1)
})
}
.width('70%')
.height(50)
.backgroundColor(getRandomColor())
}
}
export function getRandomColor(): string {
let letters = '0123456789abcdef'
let color = '#'
for (let i = 0; i < 6; i++) {
// 生成0-15的随机数
const randomIndex = Math.floor(Math.random() * 16)
// 添加随机字符
color += letters[randomIndex]
}
return color
}