鸿蒙OS高级技巧:打造个性化动态Swiper效果
前言
在鸿蒙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;
}
@Component
struct 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的无限可能。
鸿蒙OS高级技巧:打造个性化动态Swiper效果的更多相关文章
- Android SurfaceView实现静态于动态画图效果
本文是基于Android的SurfaceView的动态画图效果,实现静态和动态下的正弦波画图,可作为自己做图的简单参考,废话不多说,先上图, 静态效果: 动态效果: 比较简单,代码注释的也比较详细,易 ...
- Android自定义控件 -Canvas绘制折线图(实现动态报表效果)
有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...
- 用WPF窗体打造个性化界面的图片浏览器
原文:用WPF窗体打造个性化界面的图片浏览器 本文使用WPF窗体(XAML及C#)与Win Form控件(FolderBrowserDialog)结合的方式, 演示制作了一个简易漂亮的WPF图片浏览器 ...
- 华为鸿蒙OS发布!方舟支持混合编译,终将可替换安卓?
前言 有关于鸿蒙的消息之前也有说过,就在昨天下午,华为举行了2019开发大会,正式推出了鸿蒙os系统(Harmony).其相关负责人表示,也是基于微软内核的全场景分布式OS 鸿蒙凭借微内核的优势, ...
- 鸿蒙OS与谷歌Fuchsia
鸿蒙,意在“开天辟地”,它的征程是物联网.跨终端,是一款战略性产品.它真正对标的不是安卓,而是谷歌最新研发的操作系统Fuchsia. 根据Fuchsia中文社区的介绍,在安卓和 Chrome OS 两 ...
- 【转帖】知乎管理华为鸿蒙OS的介绍2
作者:虎游链接:https://www.zhihu.com/question/328382980/answer/784629132来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- 【转帖】知乎关于鸿蒙OS的思考
作者:bacon xu链接:https://www.zhihu.com/question/339567108/answer/782431141来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...
- Canvas之动态波浪效果_陈在真Sunny_chen_新浪博客
Canvas之动态波浪效果_陈在真Sunny_chen_新浪博客 Canvas之动态波浪效果 (2012-04-26 09:04:51) 转载▼
- 在WPF中使用PlaneProjection模拟动态3D效果
原文:在WPF中使用PlaneProjection模拟动态3D效果 虽然在WPF中也集成了3D呈现的功能,在简单的3D应用中,有时候并不需要真实光影的3D场景.毕竟使用3D引擎会消耗很多资源,有时候使 ...
- OpenGL 画出雷达动态扫描效果(二) 非底图
OpenGL 画出雷达动态扫描效果(一)中给出了已一张图片作为底图的雷达扫面程序 如果有漂亮的雷达底图的话,效果应该非常不错的,另外也可以直接手绘雷达框架 效果如下 雷达主体代码 glLineWidt ...
随机推荐
- JavaScript对象获取属性的方法(.和[]方式)
js对象获取属性有两种方法:1.通过.的方式 2. 通过[]方式 // 通过.方式获取属性值,key是静态的 var aa = {name: "zhang", age: 18}; ...
- 开源 PHP 商城项目 CRMEB 安装和使用教程
说到电商系统,很多人第一反应可能是 Shopify 或 Magento.没错,这些平台确实功能强大,但是...它们也太强大了,不仅复杂还昂贵,对于刚起步的创业者来说简直是压力山大. 但是从零开始开发一 ...
- Java面试题中高级进阶(JVM篇01)
前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说堆和栈的区别?什么时候会触发FullGC?什么是Java虚拟机?似乎有点模糊了,那就大概看一下面试题吧.好记性不如烂键盘 *** 12 ...
- 基于Java+SpringBoot+Mysql实现的快递柜寄取快递系统功能实现三
一.前言介绍: 1.1 项目摘要 随着电子商务的迅猛发展和城市化进程的加快,快递业务量呈现出爆炸式增长的趋势.传统的快递寄取方式,如人工配送和定点领取,已经无法满足现代社会的快速.便捷需求.这些问题不 ...
- delphi Image32 之 快速入门
官方快速入门,加上了一些注解 [从WORD粘贴后失去了样式] TImage32 类是关键.TImage32 对象包含单个图像,所有图像操作都作用于此对象. uses Img32; //引用单元 .. ...
- (Python基础教程之十六)Python multidict示例–将单个键映射到字典中的多个值
1.什么是multidict词典> 在python中," multidict "一词用于指代字典,在字典中可以将单个键映射到多个值.例如 多重结构 multidictWith ...
- Ollma本地部署Qwen2.5 14B(不使用docker)
部署机器硬件情况: 内存 :32GB 显卡 :3060 为什么不使用docker: 1.网上教程大多以docker为主 2.安装docker的时间太长,在等待的时候顺便尝试一下不用docker的部署 ...
- python之Marshmallow
文档说明:https://marshmallow.readthedocs.io marshmallow是一个用来将复杂的orm对象与python原生数据类型之间相互转换的库,简而言之,就是实现obje ...
- 设计模式:可复用面向对象软件的基础 pdf电子书分享
<设计模式:可复用面向对象软件的基础>是引导读者走出软件设计迷宫的指路明灯,凝聚了软件开发界几十年设计经验的结晶.四位顶尖的面向对象领域专家精心选取了最具价值的设计实践,加以分类整理和命名 ...
- MySQL中INSERT INTO ... ON DUPLICATE KEY UPDATE浅析
最近在做一个阅读次数的需求的时候,有这样一个场景,如果数据库中没有数据,就进行INSERT操作,有数据的话,阅读次数就+1.此处有两种实现方式,一种是想将数据查出来,在Java中进行处理,没有就INS ...