Swiper轮播图带放大缩小动效实践

Swiper轮播图带放大缩小动效实践

HarmonyOS
2024-05-23 23:08:27
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
xiaohur

Swiper实现轮播图基本用法

通过LazyForeach加载数据源,Swiper属于滚动组件,可以设置SwiperController配合使用,能够控制Swiper组件的滚动操作。

数据源

LazyForeach加载的数据源使用IDataSource定义,可以优化子组件渲染效率,详细原理和使用说明见LazyForEach:数据懒加载

1. 定义数据源类

class MyDataSource implements IDataSource { 
  private list: string[] = [] 
  constructor(list: string[]) { 
    this.list = list 
  } 
  totalCount(): number { 
    return this.list.length 
  } 
  getData(index: number): string { 
    return this.list[index] 
  } 
  registerDataChangeListener(listener: DataChangeListener): void { 
  } 
  unregisterDataChangeListener() { 
  } 
}

2. 定义数据源变量,模拟数据

private data: MyDataSource = new MyDataSource([]) 
aboutToAppear(): void { 
  let list: string[] = [] 
  for (let i = 0; i <= 5; i++) { 
    list.push(i.toString()); 
  } 
  this.data = new MyDataSource(list) 
}

定义SwiperController

给组件绑定一个控制器,用来控制组件翻页,能满足更多业务场景需求。

private swiperController: SwiperController = new SwiperController()

初始化Swiper组件

Swiper(this.swiperController) { 
  LazyForEach(this.data, (item: string, index: number) => { 
    Column() { 
      Text(item) 
        .width(40) 
        .height(40) 
        .textAlign(TextAlign.Center) 
        .fontSize(30) 
    } 
    .width("100%") 
    .height('100%') 
    .backgroundColor(0xFFFF00) 
  }, (item: string, index: number) => item) 
}

Swiper实现轮播图常用属性设置

通过以下常用属性设置,可以实现平滑轮播图的效果

1. 设置当前在容器中显示的子组件的索引值,在Swiper滚动过程中,此值会变化,通过状态变量可以实现滚动后子视图的属性变化。

@State  currentIndex: number = 0

2. 对应Swiper属性设置为

.index(this.currentIndex)

3. 设置一页内元素显示个数

.displayCount(1)

4. 设置当前显示子组件的前后边距,可以显示前后一项的部分视图

.nextMargin(40)  
.prevMargin(40)

5. 设置滚动轮播属性:autoPlay是否自动滚动,loop是否循环滚动,duration滚动一页时间,curve滚动动画类型

.autoPlay(true) 
.loop(true) 
.duration(500) 
.curve(Curve.Linear)

通过状态变量和滚动属性对子组件缩放

1. 定义数据源对应的缩放数组

@State scaleArray:   number[] = [];

2. 定义最大,最小缩放比例

const MAX_SCALE = 1    // 最大缩放  const MIN_SCALE = 0.8  // 最小缩放

3. 与数据源对应的缩放系数存入数组(aboutToAppear)

this.scaleArray.push(i == 0 ? MAX_SCALE : MIN_SCALE)

4. 当前显示index发生变化时,修改缩放数组的对应的缩放系数

.onChange((index: number) => {   this.currentIndex = index   this.scaleArray[this.currentIndex] = MAX_SCALE;   if (this.currentIndex == 0) {     this.scaleArray[this.scaleArray.length - 1] = MIN_SCALE   } else     this.scaleArray[this.currentIndex -1] = MIN_SCALE   if (this.currentIndex == this.scaleArray.length - 1) {     this.scaleArray[0] = MIN_SCALE   } else     this.scaleArray[this.currentIndex + 1] = MIN_SCALE })

5. 定义手势触发时的offset

startSwiperOffset:  number = 0

6. 监听手势滑动,根据滑动距离计算实时缩放系数

.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => { 
  if (this.startSwiperOffset == 0) this.startSwiperOffset = extraInfo.currentOffset; 
  let offset: number = extraInfo.currentOffset 
  let currentScale: number = this.scaleArray[index] 
  let nextIndex = (index == this.scaleArray.length - 1 ? 0 : index + 1) 
  let preIndex = (index == 0 ? this.scaleArray.length - 1 : index - 1) 
  let nextScale: number = this.scaleArray[nextIndex] 
  let preScale: number = this.scaleArray[preIndex] 
  // 滑动距离 
  let distance = Math.abs(this.startSwiperOffset - offset) 
  currentScale = MAX_SCALE - Math.min(distance / DRAGGING_MAX_DISTANCE, MAX_SCALE - MIN_SCALE) 
  if (this.startSwiperOffset > offset) { 
    nextScale = MIN_SCALE + Math.min(distance / DRAGGING_MAX_DISTANCE, MAX_SCALE - MIN_SCALE) 
    preScale = MIN_SCALE 
  } else { 
    preScale = MIN_SCALE + Math.min(distance / DRAGGING_MAX_DISTANCE, MAX_SCALE - MIN_SCALE) 
    nextScale = MIN_SCALE 
  } 
  this.scaleArray[this.currentIndex] = currentScale 
  this.scaleArray[nextIndex] = nextScale 
  this.scaleArray[preIndex] = preScale 
})

7. 手势结束后,继续监听滚动开始

.onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => { 
  if (index == targetIndex) { 
    let nextIndex = (index == this.scaleArray.length - 1 ? 0 : index + 1) 
    let preIndex = (index == 0 ? this.scaleArray.length - 1 : index - 1) 
    this.scaleArray[index] = MAX_SCALE 
    this.scaleArray[nextIndex] = MIN_SCALE 
    this.scaleArray[preIndex] = MIN_SCALE 
  } else { 
    let nextIndex = (targetIndex == this.scaleArray.length - 1 ? 0 : targetIndex + 1) 
    let preIndex = (targetIndex == 0 ? this.scaleArray.length - 1 : targetIndex - 1) 
    this.scaleArray[targetIndex] = MAX_SCALE 
    this.scaleArray[nextIndex] = MIN_SCALE 
    this.scaleArray[preIndex] = MIN_SCALE 
  } 
})

8. 手势结束后,继续监听滚动结束,startSwiperOffset归0

this.startSwiperOffset  = 0

子组件添加动画

为子组件添加动画效果,让缩放更加流畅丝滑

1. 设置scale属性,使用状态变量this.scaleArray中的缩放系数

.scale({ x: this.scaleArray[index], y: this.scaleArray[index] })

2. 设置动画效果

.animation({duration:PAGE_DURATION, curve:Curve.Linear })

实现效果

Swiper组件实现缩放轮播图完成

至此主要用到了Swiper组件和状态变量来刷新子组件的原理,数据和性能方面优化还有待加强。

分享
微博
QQ
微信
回复
2024-05-24 22:58:40
相关问题
HarmonyOS 点击图片放大缩小
38浏览 • 1回复 待解决
HarmonyOS 如何实现放大缩小的动画?
399浏览 • 1回复 待解决
HarmonyOS 相机预览是否支持放大缩小
36浏览 • 1回复 待解决