属性动画
组件的某些通用属性变化时,可以通过属性动画实现渐变过渡效果,提升用户体验。支持的属性包括width、height、backgroundColor、opacity、scale、rotate、translate等
animation(value: {duration?: number, tempo?: number, curve?: string | Curve | ICurve, delay?:number, iterations: number, playMode?: PlayMode, onFinish?: () => void})
识别组件的可动画属性变化,自动添加动画,animation只会作用于在其之上的属性调用
// 示例
.animation({
// 动画时长,默认1000毫秒
duration: 1200,
// 播放速度,默认为1
tempo: 1,
// 动画曲线
curve: Curve.Friction,
// 动画延迟执行时长,默认0,不延迟
delay: 500,
// 动画播放次数,默认1,-1:无限循环,0:无动画效果
iterations: -1, // 设置-1表示动画无限循环
// 动画播放模式
// Alternate: 奇数次正向,偶数次反向
// AlternateReverse:奇数次反向,偶数次正向
// Reverse:反向
// Normal:正常播放
playMode: PlayMode.Alternate,
// 播放完成回调
onFinish: () => {}
})
显式动画
提供全局animateTo显式动画接口来指定由于闭包代码导致的状态变化插入过渡动效。
// AnimateParam 参数同属性动画
animateTo(value: AnimateParam, event: () => void): void
示例
animateTo({ duration: 1200, curve: Curve.Friction, delay: 500, iterations: -1, // 设置-1表示动画无限循环 playMode: PlayMode.Alternate, onFinish: () => { console.info('play end') } }, () => { this.rotateAngle = 90 }) })
转场动画
-
页面间转场
在全局pageTransition方法内配置页面入场和页面退场时的自定义转场动效。
@Entry @Component struct PageTransitionExample1 { @State scale1: number = 1 @State opacity1: number = 1 build() { Column() { Navigator({ target: 'pages/page1', type: NavigationType.Push }) { Image($r('app.media.bg1')).width('100%').height('100%') // 图片存放在media文件夹下 } }.scale({ x: this.scale1 }).opacity(this.opacity1) } // pageTransition() { PageTransitionEnter({ duration: 1200, curve: Curve.Linear }) .onEnter((type: RouteType, progress: number) => { this.scale1 = 1 this.opacity1 = progress }) // 进场过程中会逐帧触发onEnter回调 PageTransitionExit({ duration: 1500, curve: Curve.Ease }) .onExit((type: RouteType, progress: number) => { this.scale1 = 1 - progress this.opacity1 = 1 }) // 退场过程中会逐帧触发onExit回调 } } -
共享元素转场
当路由进行切换时,可以通过设置组件的 sharedTransition 属性将该元素标记为共享元素并设置对应的共享元素转场动效。
示例:
// 页面A build() { Column({space: 20}) { Image("https://p.qqan.com/up/2024-5/20245101125138293.jpg") .width(200) .aspectRatio(1) .borderRadius(8) // 组件共享转场 // id: 不为空的组件即位共享元素 // duration: 时长 // curve:曲线样式 // delay:延迟时间 // motionPath: 动画路径 // type:type为SharedTransitionEffectType.Exchange时motionPath才会生效。默认值Exchange .sharedTransition("dog", { duration: 500 }) Button("跳转到B") .onClick(() => { router.pushUrl({ url: "pages/AnimationCase/SharedPageB" }) }) } .width('100%') .height('100%') } // 页面B build() { Column() { Image("https://p.qqan.com/up/2024-5/20245101125138293.jpg") .width('100%') .aspectRatio(1) .borderRadius(10) .sharedTransition("dog", { duration: 500 }) } .width('100%') .height('100%') } -
组件内转场
组件内转场主要通过transition属性配置转场参数,在组件插入和删除时显示过渡动效,主要用于容器组件中的子组件插入和删除时,提升用户体验。 示例代码
@Entry @Component struct TransitionEffectPage { @State isShow: boolean = false; build() { Column() { Column() { if (this.isShow) { Image("https://p.qqan.com/up/2024-5/20245101125138293.jpg") .width(100) .height(100) .borderRadius(50) // 组件内转场 .transition( // 进入和退出使用相同动画 // TransitionEffect.OPACITY.animation({duration: 1000}) // .combine(TransitionEffect.rotate({angle: -180})) // .combine(TransitionEffect.scale({x: 0.1, y: 0.1})) // .combine(TransitionEffect.move(TransitionEdge.START)) // 分别设置进入和退出时的动画 TransitionEffect.asymmetric( // 进入时的动画 TransitionEffect.OPACITY.animation({duration: 1000}) .combine(TransitionEffect.rotate({angle: -180})) .combine(TransitionEffect.scale({x: 0.1, y: 0.1})) .combine(TransitionEffect.move(TransitionEdge.START)), // 退出时的动画 TransitionEffect.OPACITY.animation({duration: 1000}) .combine(TransitionEffect.rotate({angle: 180})) .combine(TransitionEffect.scale({x: 0.1, y: 0.1})) .combine(TransitionEffect.move(TransitionEdge.END)) ) ) } }.height(100) Button("组件内动画") .onClick(() => { this.isShow = !this.isShow }) } .justifyContent(FlexAlign.Center) .width('100%') .height('100%') } }
路径动画
设置组件进行位移动画时的运动路径
示例
```
// xxx.ets
@Entry
@Component
struct MotionPathExample {
@State toggle: boolean = true
build() {
Column() {
Button('click me').margin(50)
// 执行动画:从起点移动到(300,200),再到(300,500),再到终点
// path:位移动画的运动路径
// from:运动路径的起点
// to:运动路径的终点
// rotatable:是否跟随路径进行旋转
.motionPath({ path: 'Mstart.x start.y L300 200 L300 500 Lend.x end.y', from: 0.0, to: 1.0, rotatable: true })
.onClick(() => {
animateTo({ duration: 4000, curve: Curve.Linear }, () => {
this.toggle = !this.toggle // 通过this.toggle变化组件的位置
})
})
}.width('100%').height('100%').alignItems(this.toggle ? HorizontalAlign.Start : HorizontalAlign.Center)
}
}
```
帧动画
-
鸿蒙提供帧动画组件来实现逐帧播放图片的能力,可以配置需要播放的图片列表,每张图片可以配置时长
-
如果用的是资源的地址 。$r("app.media.a") 这个地址不允许动态生成 代码示例
@Entry @Component struct ImageAnimatorCase { @State state: AnimationStatus = AnimationStatus.Initial build() { Row() { Column() { ImageAnimator() // 图片帧信息集合 .images([{ src: '/assets/帧动画/微信-小狗/watch-loadingdog-0@2x.png' },{ src: '/assets/帧动画/微信-小狗/watch-loadingdog-1@2x.png' },{ src: '/assets/帧动画/微信-小狗/watch-loadingdog-2@2x.png' },{ src: '/assets/帧动画/微信-小狗/watch-loadingdog-3@2x.png' }]) // 播放时长,当images中任意一帧图片设置了单独的duration后,该属性设置无效。 .duration(200) // 初始状态,于控制播放状态,默认值:AnimationStatus.Initial .state(this.state) // 是否从最后一张图片开始播放到第一张图片,默认为false .reverse(false) // 动画开始前和结束后的状态,默认为Forwards // None动画未执行时不会将任何样式应用于目标,动画播放完成之后恢复初始默认状态。 // Forwards目标将保留动画执行期间最后一个关键帧的状态。 // Backwards,动画将在应用于目标时立即应用第一个关键帧中定义的值,并在delay期间保留此值。第一个关键帧取决于playMode,playMode为Normal或Alternate时为from的状态,playMode为Reverse或AlternateReverse时为to的状态。 // Both动画将遵循Forwards和Backwards的规则,从而在两个方向上扩展动画属性。 .fillMode(FillMode.None) // 播放次数 .iterations(-1) // 设置图片大小是否固定为组件大小。 true表示图片大小与组件大小一致,此时设置图片的width 、height 、top 和left属性是无效的。false表示每一张图片的width 、height 、top和left属性都要单独设置。 // 默认值:true .fixedSize(true) .width(340) .height(240) ImageAnimator() .images([{ src: '/assets/帧动画/小米有品/bigtap_queue_1@3x.png' },{ src: '/assets/帧动画/小米有品/bigtap_queue_2@3x.png' },{ src: '/assets/帧动画/小米有品/bigtap_queue_3@3x.png' },{ src: '/assets/帧动画/小米有品/bigtap_queue_4@3x.png' }]) .duration(200) .state(this.state) .fillMode(FillMode.None) .iterations(-1) .width(340) .height(240) Button("帧动画") .onClick(() => { if(this.state === AnimationStatus.Running) { this.state = AnimationStatus.Paused return } this.state = AnimationStatus.Running }) } .width('100%') } .height('100%') } } -
帧动画支持的事件