写点什么

鸿蒙 OS 高级技巧:打造个性化动态 Swiper 效果

  • 2024-10-27
    北京
  • 本文字数:3607 字

    阅读完需:约 12 分钟

前言

在鸿蒙 OS 的广阔天地中,开发者们有机会创造出令人惊叹的用户体验。最近,我着手设计一款具有独特滑动效果的 Swiper 组件,它在滑动时能够迅速进入视野,同时巧妙地将旧的 cell 隐藏到视线之外。本文将分享如何利用鸿蒙的 Swiper 组件,实现这一引人入胜的动态效果。



一、设计与构思

Swiper 的设计理念是简洁而富有动感。每个 cell 在滑动时不仅会逐渐缩小至原始大小的 70%,还会被前一个 cell 覆盖,创造出一种流畅且连续的视觉效果。这种效果的实现,依赖于精确的动画控制和布局调整。

二、代码设计与实现思路

实现这一效果,我们需要对 Swiper 组件进行深度定制。这包括对 cell 的尺寸、位置和层级进行动态调整,以及利用贝塞尔曲线来实现平滑的动画效果。

三、控件采用与代码说明

3.1 Swiper 组件定制

Swiper 组件提供了丰富的 API,允许我们对其行为进行精细控制。以下是一些关键的配置项和它们的作用:


  • itemSpace: 控制 cell 之间的间距。

  • indicator: 是否显示指示器。

  • displayCount: 设置同时展示的 cell 数量。

  • onAreaChange: 当 Swiper 区域大小变化时的回调。

  • customContentTransition: 自定义内容转换动画。


Swiper 组件基础配置代码:


Swiper()  .itemSpace(12)  .indicator(false)  .displayCount(this.DISPLAY_COUNT)  .padding({left:10, right:10})  .onAreaChange((oldValue, newValue) => {    // 处理区域变化逻辑  })  .customContentTransition({    transition: (proxy) => {      // 自定义转换逻辑    }  });
复制代码
3.2 Item 组件设置

每个 Item 需要根据其在 Swiper 中的位置进行尺寸、位置和层级的调整。这涉及到初始化相关变量,并在aboutToAppear生命周期方法中进行设置。


初始化宽高,初始化组件数据:


  @State cw: number = 0;  @State ch: number = 0;    aboutToAppear(): void {    initSwipe(...)  }
initSwipe(num:number){ this.translateList = [] for (let i = 0; i < num; i++) { this.scaleList.push(0.8) this.translateList.push(0.0) this.zIndexList.push(0) } } private MIN_SCALE: number = 0.70 private DISPLAY_COUNT: number = 4 private DISPLAY_WIDTH: number = 200 @State scaleList: number[] = [] @State translateList: number[] = [] @State zIndexList: number[] = []
复制代码


Item 尺寸和位置设置代码:


LifeStyleItem({lifeStyleResponse: item})  .scale({ x: this.scaleList[index], y: this.scaleList[index] })  .translate({ x: this.translateList[index] })  .zIndex(this.zIndexList[index]);
复制代码


在 customContentTransition 的 transition 属性中设置属性:



//scaleList 需要进行线性变化//translateList 位移需要进行 数据偏移处理和贝塞尔曲线处理//zIndexList 需要进行位置层级设置
this.scaleList[proxy.index] = 线性函数this.translateList[proxy.index] = - proxy.position * proxy.mainAxisLength + 贝塞尔曲线函数this.zIndexList[proxy.index] = proxy.position
复制代码
3.3 自定义动画效果

为了实现平滑的动画效果,我们定义了三次贝塞尔曲线函数和线性函数。这些函数将用于计算 cell 在滑动过程中的尺寸、位置和层级变化。


三次贝塞尔曲线函数:


function cubicBezier8(t, a1, b1, a2, b2) {  // 计算三次贝塞尔曲线的值  const k1 = 3 * a1;const k2 = 3 * (a2 - b1) - k1;const k3 = 1 - k1 - k2;return k3 * Math.pow(t, 3) + k2 * Math.pow(t, 2) + k1 * t;
}
复制代码


线性函数:


function chazhi(startPosition, endPosition, startValue, endValue, position) {  // 计算线性插值的结果 
const range = endPosition - startPosition;const positionDifference = position - startPosition;const fraction = positionDifference / range;
const valueRange = endValue - startValue;const result = startValue + (valueRange * fraction);
return result;
}
复制代码
3.4 计算函数实现

我们编写了计算函数来确定 cell 在 Swiper 中的最终表现。这包括根据位置计算尺寸、位置和层级。


计算尺寸和位置的函数:


function calculateValue(width: number, position: number): number {  const minValue = 0;
const normalizedPosition = position / 4;
// 计算贝塞尔曲线的缓动值 const easedPosition = cubicBezier(normalizedPosition, 0.3, 0.1, 1, 0.05);
// 根据缓动值计算最终的变化值 const value = minValue + (width - minValue) * easedPosition; return value;}
function calculateValueScale(position) {
if (position >= 2.5) { // 当position大于2时,值固定为0.8 return 0.8;} else if (position < 2.5) { const startPosition = 2.5; const endPosition = -1; // 定义返回值的起始值和结束值 const startValue = 0.8; const endValue = 0.7; return chazhi(startPosition,endPosition,startValue,endValue,position)}
return 0.7;
}
复制代码

四、全部代码整合

将上述所有代码片段整合到一个组件中,确保 Swiper 和每个 Item 都能够根据用户的滑动操作动态调整。代码如下:



function calculateValue(width: number, position: number): number { const minValue = 0; const normalizedPosition = position / 4; const easedPosition = cubicBezier8(normalizedPosition, 0.3, 0.1, 1, 0.05); const value = minValue + (width - minValue) * easedPosition; return value;}
function cubicBezier(t: number, a1: number, b1: number, a2: number, b2: number): number { const k1 = 3 * a1; const k2 = 3 * (a2 - b1) - k1; const k3 = 1 - k1 - k2; return k3 * Math.pow(t, 3) + k2 * Math.pow(t, 2) + k1 * t;}
function calculateValueScale(position: number): number { if (position >= 2.5) { return 0.8; } else if (position < 2.5) { const startPosition = 2.5; const endPosition = -1; const startValue = 0.8; const endValue = 0.7; return chazhi(startPosition,endPosition,startValue,endValue,position) } return 0.7;}
function chazhi(startPosition:number,endPosition:number,startValue:number,endValue:number,position:number):number{
const range = endPosition - startPosition; const positionDifference = position - startPosition; const fraction = positionDifference / range;
const valueRange = endValue - startValue; const result = startValue + (valueRange * fraction);
return result;}
@Componentstruct Banner { @State cw: number = 0; @State ch: number = 0; aboutToAppear(): void { initSwipe() }
initSwipe(num:number){ this.translateList = [] for (let i = 0; i < num; i++) { this.scaleList.push(0.8) this.translateList.push(0.0) this.zIndexList.push(0) } } private MIN_SCALE: number = 0.70 private DISPLAY_COUNT: number = 4 private DISPLAY_WIDTH: number = 200 @State scaleList: number[] = [] @State translateList: number[] = [] @State zIndexList: number[] = [] build(){ Swiper() { ForEach(this.lifeStyleList, (item: LifeStyleResponse|null,index) => { LifeStyleItem({lifeStyleResponse:item}) .scale({ x: this.scaleList[index], y: this.scaleList[index] }) .translate({ x: this.translateList[index] }) .zIndex(this.zIndexList[index]) } ) } .itemSpace(12) .indicator(false) .displayCount(this.DISPLAY_COUNT) .padding({left:10,right:10}) .onAreaChange((oldValue,newValue)=>{ this.cw = new Number(newValue.width).valueOf() this.ch = new Number(newValue.height).valueOf() }) .customContentTransition({ transition :(proxy: SwiperContentTransitionProxy)=>{ this.scaleList[proxy.index] = calculateValueScale(proxy.position) this.translateList[proxy.index] = - proxy.position * proxy.mainAxisLength + calculateValue8(this.cw,proxy.position) this.zIndexList[proxy.index] = proxy.position } }) }
复制代码

五、总结

通过本文的深入解析,我们不仅实现了一个具有个性化动态效果的 Swiper 组件,还学习了如何利用鸿蒙 OS 的强大 API 来定制动画和布局。希望这篇文章能够激发更多开发者的创造力,共同探索鸿蒙 OS 的无限可能。

发布于: 刚刚阅读数: 6
用户头像

还未添加个人签名 2021-11-19 加入

还未添加个人简介

评论

发布
暂无评论
鸿蒙OS高级技巧:打造个性化动态Swiper效果_鸿蒙_王二蛋和他的张大花_InfoQ写作社区