鸿蒙应用如何实现超级丝滑的动画
统一管理:使用工具类集中管理所有动画效果性能优先:提供动画开关,支持多档速度用户体验:使用弹性曲线,控制合理时长代码复用:封装通用动画,减少重复代码灵活配置:支持全局配置和局部定制。
目录
动画系统架构
1. 统一动画管理
项目采用集中式动画管理方案,通过 Animation.ets 工具类统一管理所有动画效果:
// entry/src/main/ets/common/utils/Animation.ets
class AnimationUtil {
// 转场缩放动画
public isScaleTran(i: number, uiConfig: UIConfig) { }
// 转场滑动动画
public isSlide(i: number, uiConfig: UIConfig) { }
// 点击动效
public isClickEffect(uiConfig: UIConfig) { }
// 图标动效
public isIconEffect(uiConfig: UIConfig) { }
}
export const customAnimationUtil = new AnimationUtil()
2. 动画配置系统
通过 UIConfig 类实现全局动画配置:
export class UIConfig {
// 动画开关
isAnimation: boolean = true
// 动画速度(毫秒)
animationSpeed: number = 300
// 动画速度档位索引
animationSpeedIndex: number = 1 // 0:快速, 1:正常, 2:慢速, 3:关闭
// 震动反馈
isVibrate: boolean = true
// 按钮位置索引(影响按钮动画方向)
buttonPositionIndex: number = 0
}
核心动画类型
1. 转场动画 (TransitionEffect)
1.1 缩放转场动画
实现原理:组件出现时从缩放为0逐渐放大到正常大小,配合透明度变化
public isScaleTran(i: number, uiConfig: UIConfig) {
return uiConfig.isAnimation ?
TransitionEffect.OPACITY
.combine(TransitionEffect.scale({x: 0, y: 0}))
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(), // 弹性曲线
delay: i * 10 + 30 // 递增延迟,实现瀑布流效果
})
: null
}
使用场景:
-
列表项加载
-
卡片展示
-
配置项显示
实际应用:
// 配置列表项
ListItem() {
// ... 内容
}
.transition(customAnimationUtil.isScaleTran(index, this.uiConfig))
1.2 滑动转场动画
从左到右滑入:
public isSlide(i: number, uiConfig: UIConfig) {
return uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.SLIDE)
: null
}
从右到左滑入:
public isSlideR(i: number, uiConfig: UIConfig) {
return uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.translate({x: 20}))
: null
}
1.3 非对称转场动画
应用场景:按钮位置切换时的不同进出动画
public isSlideSwitch(uiConfig: UIConfig) {
return uiConfig.isAnimation ?
(uiConfig.buttonPositionIndex === 0 ?
TransitionEffect.asymmetric(
// 进入动画
TransitionEffect.OPACITY
.animation({ duration: uiConfig.animationSpeed, curve: curves.springMotion(), delay: 50 })
.combine(TransitionEffect.SLIDE_SWITCH),
// 退出动画
TransitionEffect.OPACITY
.animation({ duration: uiConfig.animationSpeed, curve: curves.springMotion(), delay: 50 })
.combine(TransitionEffect.SLIDE)
)
: /* 其他位置的动画 */)
: null
}
2. 显式动画 (animateTo)
2.1 基本用法
实现原理:通过 animateTo 函数包裹状态变化,实现平滑过渡
// 切换代理组
animateTo({
duration: this.uiConfig.animationSpeed
}, () => {
this.currentProxyIndex = targetIndex
})
2.2 配合 Swiper 组件
// 同步 Swiper 切换动画
animateTo({ duration: this.uiConfig.animationSpeed }, () => {
this.currentProxyIndex = targetIndex
})
this.SwiperController.changeIndex(
targetIndex,
this.uiConfig.animationSpeed != 0 ? true : false
)
2.3 卡片编辑动画
// 点击卡片显示/隐藏
.onClick(() => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: curves.springMotion()
}, () => {
this.theCurrentHomeCard.splice(i, 1, isShow)
})
})
3. 属性动画
3.1 宽度/高度动画
圆形按钮展开为胶囊按钮:
Column() {
Row() {
SymbolGlyph(this.Switch ? this.Icon1 : this.Icon2)
.fontSize(24)
Text(this.SubText)
.fontSize(20)
.fontColor(this.Switch ? Color.White : Color.Transparent)
}
}
.width(this.Switch ?
$r('app.integer.vp_proxy_started_button_width') : // 展开宽度
$r('app.integer.vp_proxy_not_start_button_width') // 收缩宽度
)
.height($r('app.integer.vp_proxy_not_start_button_height'))
.animation({
duration: this.uiConfig.animationSpeed,
curve: curves.springMotion()
})
3.2 旋转动画
无限循环旋转:
startAnim() {
this.rotateAngle = 0
animateTo({
duration: this.uiConfig.animationSpeed,
curve: Curve.Linear,
iterations: -1, // 无限循环
playMode: PlayMode.Alternate // 往返播放
}, () => {
this.rotateAngle = 1
})
}
// 应用旋转
.rotate({
angle: this.uiConfig.isAnimation ? this.rotateAngle : null
})
3.3 缩放动画
标签页图标缩放:
.scale(this.tabsSelect.swiperPage == n.swiperPage ?
{x: this.tabsIconScale, y: this.tabsIconScale} :
{x: 1, y: 1}
)
.onTouch((event: TouchEvent) => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: Curve.Ease,
}, () => {
if (event.type == TouchType.Down) {
this.tabsIconScale = 0.8 // 按下缩小
} else if (event.type == TouchType.Up) {
this.tabsIconScale = 1 // 松开恢复
}
})
})
4. 交互动效
4.1 点击动效 (ClickEffect)
实现原理:点击时组件缩小,松开后恢复
public isClickEffect(uiConfig: UIConfig) {
return uiConfig.isAnimation ?
{
level: ClickEffectLevel.MIDDLE, // 中等强度
scale: 0.95 // 缩放到95%
}
: null
}
// 使用
.clickEffect(customAnimationUtil.isClickEffect(this.uiConfig))
4.2 图标动效 (SymbolEffect)
实现原理:系统图标的内置动画效果
public isIconEffect(uiConfig: UIConfig) {
return uiConfig.isAnimation ?
SymbolEffectStrategy.SCALE // 缩放效果
: null
}
// 使用
SymbolGlyph($r('sys.symbol.play'))
.effectStrategy(customAnimationUtil.isIconEffect(this.uiConfig))
4.3 悬停效果 (HoverEffect)
.hoverEffect(HoverEffect.Scale) // 悬停时缩放
5. 手势动画
5.1 Swiper 滑动动画
Swiper(this.SwiperController) {
// 内容
}
.indicator(false)
.loop(false)
.duration(this.uiConfig.animationSpeed)
.curve(Curve.EaseInOut)
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
animateTo({ duration: this.uiConfig.animationSpeed }, () => {
// 处理滑动逻辑
})
})
.onAnimationStart((index: number, targetIndex: number) => {
animateTo({ duration: this.uiConfig.animationSpeed }, () => {
this.currentProxyIndex = targetIndex
})
})
5.2 触摸反馈动画
.onTouch((event: TouchEvent) => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: Curve.Ease,
}, () => {
if (event.type == TouchType.Down) {
this.switchTranslateX(i)
this.tabsSelect.swiperPage = n.swiperPage
this.tabsIconScale = 0.8
} else if (event.type == TouchType.Up) {
this.tabsIconScale = 1
}
})
})
动画工具类实现
完整工具类代码
import { UIConfig } from "../../entryability/AppState"
import { curves } from "@kit.ArkUI"
let effectEvent: TransitionEffect | null
let clickEffect: ClickEffect | null
let iconEffect: SymbolEffectStrategy | null
class AnimationUtil {
// 1. 转场缩放动画(标准延迟)
public isScaleTran(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.combine(TransitionEffect.scale({x: 0, y: 0}))
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i * 10 + 30
})
: null
return effectEvent
}
// 2. 转场缩放动画(快速延迟)
public isScaleTranFast(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.combine(TransitionEffect.scale({x: 0, y: 0}))
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i * 5 + 30
})
: null
return effectEvent
}
// 3. 转场透明度动画
public isOpacity(uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: Curve.Ease,
delay: 0
})
: null
return effectEvent
}
// 4. 转场滑动动画(左到右)
public isSlide(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.SLIDE)
: null
return effectEvent
}
// 5. 转场滑动动画(右到左)
public isSlideR(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.translate({x: 20}))
: null
return effectEvent
}
// 6. 转场放大动画
public isSlideScaleBig(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.scale({x: 0, y: 0}))
: null
return effectEvent
}
// 7. 转场缩小动画(非对称)
public isSlideScaleSmall(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.asymmetric(
// 进入:从大到小
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.scale({x: 2, y: 2})),
// 退出:向上移动
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i
})
.combine(TransitionEffect.translate({y: -5}))
)
: null
return effectEvent
}
// 8. 按钮滑动切换动画
public isSlideSwitch(uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
(uiConfig.buttonPositionIndex === 0 ?
TransitionEffect.asymmetric(
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: 50
})
.combine(TransitionEffect.SLIDE_SWITCH),
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: 50
})
.combine(TransitionEffect.SLIDE)
)
: uiConfig.buttonPositionIndex === 2 ?
TransitionEffect.asymmetric(
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: 50
})
.combine(TransitionEffect.SLIDE),
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: 50
})
.combine(TransitionEffect.SLIDE_SWITCH)
)
: TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: 50
})
.combine(TransitionEffect.SLIDE_SWITCH))
: null
return effectEvent
}
// 9. 底部标签栏转场动画
public isTranslate(uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.OPACITY
.animation({
duration: uiConfig.animationSpeed,
delay: 0
})
.combine(TransitionEffect.translate({ y: 50 }))
: null
return effectEvent
}
// 10. 点击动效
public isClickEffect(uiConfig: UIConfig) {
clickEffect = uiConfig.isAnimation ?
{
level: ClickEffectLevel.MIDDLE,
scale: 0.95
}
: null
return clickEffect
}
// 11. 图标动效
public isIconEffect(uiConfig: UIConfig) {
iconEffect = uiConfig.isAnimation ?
SymbolEffectStrategy.SCALE
: null
return iconEffect
}
// 12. 图标转场缩放旋转动画
public isScaleTranIcon(i: number, uiConfig: UIConfig) {
effectEvent = uiConfig.isAnimation ?
TransitionEffect.scale({x: 0, y: 0})
.combine(TransitionEffect.rotate({angle: 360}))
.animation({
duration: uiConfig.animationSpeed,
curve: curves.springMotion(),
delay: i * 10 + 50
})
: null
return effectEvent
}
}
export const customAnimationUtil = new AnimationUtil()
使用方法
// 1. 转场动画 .transition(customAnimationUtil.isScaleTran(index, this.uiConfig)) // 2. 点击动效 .clickEffect(customAnimationUtil.isClickEffect(this.uiConfig)) // 3. 图标动效 .effectStrategy(customAnimationUtil.isIconEffect(this.uiConfig))
实战应用场景
场景1:列表项递增动画
效果:列表项依次从小到大出现,形成瀑布流效果
List() {
ForEach(this.configList, (item: ConfigData, index: number) => {
ListItem() {
// 列表项内容
}
.transition(customAnimationUtil.isScaleTran(index, this.uiConfig))
})
}
关键点:
-
使用
index作为延迟参数 -
延迟计算公式:
i * 10 + 30毫秒 -
配合
curves.springMotion()实现弹性效果
场景2:卡片展开/收起动画
效果:卡片点击后平滑展开或收起
Image($r('app.media.card_image'))
.width(w)
.height(160)
.transition(customAnimationUtil.isScaleTran(i, this.uiConfig))
.onClick(() => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: curves.springMotion()
}, () => {
this.theCurrentHomeCard.splice(i, 1, !this.theCurrentHomeCard[i])
})
})
场景3:按钮状态切换动画
效果:圆形按钮展开为胶囊按钮,显示计时器文本
Column() {
Row() {
SymbolGlyph(this.Switch ? this.Icon1 : this.Icon2)
.fontSize(24)
.effectStrategy(customAnimationUtil.isIconEffect(this.uiConfig))
Text(this.SubText)
.fontSize(20)
.fontColor(this.Switch ? Color.White : Color.Transparent)
}
}
.width(this.Switch ?
$r('app.integer.vp_proxy_started_button_width') :
$r('app.integer.vp_proxy_not_start_button_width')
)
.animation({
duration: this.uiConfig.animationSpeed,
curve: curves.springMotion()
})
.transition(customAnimationUtil.isSlideSwitch(this.uiConfig))
.clickEffect(customAnimationUtil.isClickEffect(this.uiConfig))
场景4:Swiper 页面切换动画
效果:页面滑动切换时同步更新索引和UI状态
Swiper(this.SwiperController) {
ForEach(this.theProxyGroups, (group: ProxyGroup) => {
// 页面内容
})
}
.indicator(false)
.loop(false)
.duration(this.uiConfig.animationSpeed)
.curve(Curve.EaseInOut)
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
animateTo({ duration: this.uiConfig.animationSpeed }, () => {
// 处理手势滑动逻辑
})
})
.onAnimationStart((index: number, targetIndex: number) => {
animateTo({ duration: this.uiConfig.animationSpeed }, () => {
this.ListScroller.scrollToIndex(targetIndex)
this.currentProxyIndex = targetIndex
})
})
场景5:标签页切换动画
效果:标签页图标缩放 + 指示器平移
// 标签页图标
SymbolGlyph(n.icon)
.fontSize(24)
.scale(this.tabsSelect.swiperPage == n.swiperPage ?
{x: this.tabsIconScale, y: this.tabsIconScale} :
{x: 1, y: 1}
)
.onTouch((event: TouchEvent) => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: Curve.Ease,
}, () => {
if (event.type == TouchType.Down) {
this.switchTranslateX(i)
this.tabsSelect.swiperPage = n.swiperPage
this.tabsIconScale = 0.8
} else if (event.type == TouchType.Up) {
this.tabsIconScale = 1
}
})
})
// Swiper 切换时同步动画
.onChange((index: number) => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: curves.interpolatingSpring(10, 1, 228, 30),
}, () => {
this.tabsSelect.swiperPage = targetIndex
this.switchTranslateX(targetIndex)
})
})
场景6:配置项删除动画
效果:删除按钮出现 + 列表项移除动画
if (this.isShowDeleteButton) {
Image($r('sys.symbol.xmark'))
.width(HomeCardDeleteButtonSize(this.widthBp, this.heightBp))
.height(HomeCardDeleteButtonSize(this.widthBp, this.heightBp))
.transition(customAnimationUtil.isSlideScaleSmall(0, this.uiConfig))
.onClick(() => {
animateTo({
duration: this.uiConfig.animationSpeed,
curve: curves.springMotion()
}, () => {
this.theCurrentHomeCard.splice(i, 1, false)
})
})
}
性能优化策略
1. 动画开关控制
实现方案:通过全局配置控制动画开关
export class UIConfig {
isAnimation: boolean = true // 动画总开关
animationSpeed: number = 300 // 动画速度
animationSpeedIndex: number = 1 // 速度档位
}
// 动画速度映射
const ANIMATION_SPEEDS = [150, 300, 500, 0] // 快速、正常、慢速、关闭
优势:
-
用户可根据设备性能选择动画档位
-
低端设备可关闭动画提升流畅度
-
节省电量
2. 条件性应用动画
实现方案:根据配置决定是否应用动画
.transition( uiConfig.isAnimation ? customAnimationUtil.isScaleTran(index, uiConfig) : null )
优势:
-
避免不必要的动画计算
-
减少渲染负担
3. 延迟优化
标准延迟:适用于普通列表
delay: i * 10 + 30 // 每项延迟10ms
快速延迟:适用于大量元素
delay: i * 5 + 30 // 每项延迟5ms
固定延迟:适用于单个元素
delay: 50 // 固定延迟
4. 动画曲线选择
弹性曲线 (springMotion):适用于大部分场景
curve: curves.springMotion()
-
自然的弹性效果
-
符合物理运动规律
-
用户体验最佳
线性曲线 (Linear):适用于循环动画
curve: Curve.Linear
-
匀速运动
-
适合旋转、进度条等
缓动曲线 (Ease):适用于简单过渡
curve: Curve.Ease
-
先加速后减速
-
适合透明度、位移等
插值弹簧曲线:适用于精细控制
curve: curves.interpolatingSpring(10, 1, 228, 30)
-
参数:速度、阻尼、质量、初始速度
-
可精确控制弹性效果
5. 避免过度动画
问题:同时触发过多动画导致卡顿
解决方案:
-
限制同时播放的动画数量
-
使用虚拟滚动减少渲染元素
-
大列表使用快速延迟模式
// 使用快速延迟 .transition(customAnimationUtil.isScaleTranFast(index, this.uiConfig))
6. 动画状态管理
问题:频繁切换动画状态导致性能问题
解决方案:使用标志位控制动画触发
export class isON {
toggleAnim: boolean = false // 动画触发标志
}
// 使用
.transition(this.isON.toggleAnim ? null : customAnimationUtil.isScaleTran(index, this.uiConfig))
最佳实践建议
1. 动画设计原则
1.1 一致性原则
-
同类型交互使用相同动画效果
-
统一动画时长和曲线
-
保持视觉语言一致
1.2 性能优先原则
-
优先使用 GPU 加速的属性(transform、opacity)
-
避免动画 width、height 等触发重排的属性
-
使用
scale代替width/height动画
1.3 用户体验原则
-
动画时长控制在 200-400ms
-
提供动画开关选项
-
避免过度动画干扰用户操作
2. 代码组织建议
2.1 集中管理动画配置
// 统一的动画工具类
export const customAnimationUtil = new AnimationUtil()
// 统一的配置类
@StorageLink('uiConfig') uiConfig: UIConfig = new UIConfig()
2.2 使用语义化命名
// 好的命名 isScaleTran() // 缩放转场 isSlideSwitch() // 滑动切换 isClickEffect() // 点击效果 // 避免 anim1() effect() trans()
2.3 注释说明动画效果
// 转场缩放动画,i为延迟,在list或foreach中可以将i设为index,达到递增的动画效果
public isScaleTran(i: number, uiConfig: UIConfig) {
// 实现代码
}
3. 常见动画组合
3.1 列表项出现动画
TransitionEffect.OPACITY
.combine(TransitionEffect.scale({x: 0, y: 0}))
.animation({
duration: 300,
curve: curves.springMotion(),
delay: index * 10 + 30
})
3.2 页面切换动画
TransitionEffect.asymmetric(
TransitionEffect.move(TransitionEdge.END),
TransitionEffect.move(TransitionEdge.START)
)
.animation({ duration: 300, curve: Curve.Ease })
.combine(TransitionEffect.OPACITY)
3.3 按钮交互动画
// 点击缩放
.clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.95 })
// 悬停效果
.hoverEffect(HoverEffect.Scale)
// 图标动效
.effectStrategy(SymbolEffectStrategy.SCALE)
4. 动画调试技巧
4.1 动画速度调试
// 开发时使用慢速动画便于观察 const DEBUG_MODE = true const animationSpeed = DEBUG_MODE ? 1000 : 300
4.2 动画开关调试
// 快速切换动画开关测试性能
@StorageLink('uiConfig') uiConfig: UIConfig = new UIConfig()
// 在设置页提供开关
Toggle({ type: ToggleType.Switch, isOn: this.uiConfig.isAnimation })
.onChange((isOn: boolean) => {
this.uiConfig.isAnimation = isOn
})
4.3 日志输出
animateTo({
duration: this.uiConfig.animationSpeed,
onFinish: () => {
console.info('动画完成')
}
}, () => {
console.info('动画开始')
this.currentIndex = targetIndex
})
5. 动画性能监控
5.1 帧率监控
// 使用 HiTrace 监控动画性能
import { hiTraceMeter } from '@kit.PerformanceAnalysisKit'
hiTraceMeter.startTrace('animation_performance', 1)
animateTo({ duration: 300 }, () => {
// 动画逻辑
})
hiTraceMeter.finishTrace('animation_performance', 1)
5.2 避免动画卡顿
问题场景:
-
大量元素同时动画
-
复杂布局计算
-
频繁状态更新
解决方案:
// 1. 分批动画
ForEach(this.list, (item, index) => {
ListItem() { }
.transition(customAnimationUtil.isScaleTran(
Math.min(index, 10), // 限制最大延迟
this.uiConfig
))
})
// 2. 使用 LazyForEach
LazyForEach(this.dataSource, (item, index) => {
ListItem() { }
.transition(customAnimationUtil.isScaleTranFast(index, this.uiConfig))
})
// 3. 条件性渲染
if (this.isVisible) {
Component()
.transition(customAnimationUtil.isOpacity(this.uiConfig))
}
动画效果速查表
| 动画类型 | 方法名 | 适用场景 | 延迟参数 |
|---|---|---|---|
| 缩放转场 | isScaleTran() |
列表项、卡片 | index * 10 + 30 |
| 快速缩放转场 | isScaleTranFast() |
大量元素 | index * 5 + 30 |
| 透明度转场 | isOpacity() |
简单显隐 | 0 |
| 左滑入 | isSlide() |
页面切换 | 固定值 |
| 右滑入 | isSlideR() |
侧边栏 | 固定值 |
| 放大转场 | isSlideScaleBig() |
强调元素 | 固定值 |
| 缩小转场 | isSlideScaleSmall() |
删除动画 | 0 |
| 按钮切换 | isSlideSwitch() |
按钮状态 | 50 |
| 底部栏 | isTranslate() |
标签栏 | 0 |
| 点击效果 | isClickEffect() |
所有可点击元素 | - |
| 图标效果 | isIconEffect() |
系统图标 | - |
| 图标转场 | isScaleTranIcon() |
设置项图标 | index * 10 + 50 |
动画曲线对比
| 曲线类型 | 特点 | 适用场景 | 代码 |
|---|---|---|---|
| springMotion | 弹性效果 | 大部分场景 | curves.springMotion() |
| Linear | 匀速运动 | 循环动画 | Curve.Linear |
| Ease | 缓入缓出 | 简单过渡 | Curve.Ease |
| EaseIn | 缓入 | 元素消失 | Curve.EaseIn |
| EaseOut | 缓出 | 元素出现 | Curve.EaseOut |
| EaseInOut | 缓入缓出 | 页面切换 | Curve.EaseInOut |
| interpolatingSpring | 自定义弹簧 | 精细控制 | curves.interpolatingSpring(10, 1, 228, 30) |
总结
核心要点
-
统一管理:使用工具类集中管理所有动画效果
-
性能优先:提供动画开关,支持多档速度
-
用户体验:使用弹性曲线,控制合理时长
-
代码复用:封装通用动画,减少重复代码
-
灵活配置:支持全局配置和局部定制
实现步骤
-
创建
Animation.ets工具类 -
定义
UIConfig配置类 -
在组件中引入并使用
-
提供用户设置界面
-
测试和优化性能
推荐配置
// 推荐的动画配置
export class UIConfig {
isAnimation: boolean = true // 默认开启
animationSpeed: number = 300 // 300ms 最佳
animationSpeedIndex: number = 1 // 正常速度
}
// 推荐的动画曲线
curve: curves.springMotion() // 弹性效果最佳
// 推荐的延迟策略
delay: index * 10 + 30 // 标准列表
delay: index * 5 + 30 // 大量元素
delay: 50 // 单个元素
参考资源
更多推荐



所有评论(0)