大家好啊,这里是鸿蒙开天组,今天我们来学习属性动画-animateTo&转场动画,咱们先来学习属性动画-animateTo
属性动画-animateTo
属性动画 animation是作为属性使用,而animateTo显示动画是一个系统的内置函数,可以直接调用。功能上和 animation一致,适合于给多个元素应用同一套动画的场景
核心用法
和 animation 的核心用法步骤类似,第三步的语法需要调整
- 声明相关状态变量
- 将状态变量设置到相关可动画属性接口
- 通过属性动画接口开启属性动画(在属性动画上面的属性会应用动画)
- 通过状态变量改变UI界面
// 参数 1 动画选项 和 animation 相同
// 参数 2 箭头函数,状态变量的修改写在里面
animateTo({}, () => {// 第 4 步写到这里
})
来试一下
- 基于基础模版给页面中的尺寸添加旋转动画
- 思考如果用 animation 需要如何编码?
这里给出基础模板
@Entry
@Component
struct Page06_animateTo {// 1. 声明相关状态变量@State rotateAngle: number = 0build() {Column() {// 4个齿轮Flex({ wrap: FlexWrap.Wrap }) {Image($r('app.media.ic_gear1')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear2')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear3')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear4')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })}Button('点击旋转齿轮').onClick(() => {})}.width('100%').height('100%').backgroundColor(Color.Orange)}
}
tips:
绝大多数情况下 animation 和 animateTo可以互相替代,当多个元素应用同一个动画时,用 animateTo 会更为适合
来揭晓参考答案吧~
@Entry
@Component
struct Page06_animateTo {// 1. 声明相关状态变量@State rotateAngle: number = 0build() {Column() {// 4个齿轮Flex({ wrap: FlexWrap.Wrap }) {Image($r('app.media.ic_gear1')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear2')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear3')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })Image($r('app.media.ic_gear4')).width(150)// 2. 将状态变量设置到相关可动画属性接口.rotate({ angle: this.rotateAngle })}Button('点击旋转齿轮').onClick(() => {// 3. 通过属性动画接口开启属性动画(在属性动画上面的属性会应用动画)animateTo({ iterations: -1, curve: Curve.Linear }, () => {// 4. 通过状态变量改变UI界面this.rotateAngle = 360})})}.width('100%').height('100%').backgroundColor(Color.Orange)}
}
案例-折扣信息
还是之前的那个折扣信息案例,咱们通过 animateTo 来实现一次,来看看是否可以用 animateTo 一样的效果
需求:
- 将原模版中的 animation 替换为 animateTo
核心步骤:
- 将 animation 设置的动画属性,通过 animateTo 设置
- 调整状态变量的代码写到 animateTo 的回调函数中即可
基础代码前面的文章中已经给出,这里直接提供实现后的代码
@Entry
@Component
struct Page07_animateToDemo {// 1. 声明相关状态变量@State scaleX: number = 1@State scaleY: number = 1build() {Column({ space: 50 }) {Text('全场低至一分购').fontSize(30).fontWeight(900).fontColor(Color.Red).backgroundColor('#e8b66d').padding(10).borderRadius(20)// 2.将状态变量设置到相关可动画属性接口.scale({x: this.scaleX,y: this.scaleY}).onAppear(() => {// 3. 通过属性动画接口开启属性动画animateTo({duration: 1000,curve: Curve.EaseInOut,playMode: PlayMode.Alternate,iterations: -1}, () => {// 4.通过状态变量改变UI界面this.scaleX = 1.3this.scaleY = 1.3})})}.width('100%').height('100%').padding(20)}@StylesfullSize() {.width('100%').height('100%')}
}
转场动画
转场动画是指对将要出现或消失的组件做动画,对始终出现的组件做动画应使用属性动画。
转场动画主要有如下分类:
- 出现/消失转场
- 导航转场(和路由相关-路由阶段讲解)
- 模态转场(全模态、半模态弹框,还有一些其他的弹出菜单-链接)
- 共享元素转场(和路由相关-路由阶段讲解)
出现消失转场-核心用法
比如点击关闭广告,添加或者删除元素。核心就是元素需要出现或者消失,都可以使用转场动画来添加过渡效果
核心步骤:
- 创建TransitionEffect
- 将转场效果通过transition接口设置到组件
- 新增或者删除组件触发转场
@State isPresent: boolean = true;
...
if (this.isPresent) {Text('test').transition(effect)
}
...
// 控制新增或者删除组件
// 方式一:将控制变量放到animateTo闭包内,未通过animation接口定义动画参数的TransitionEffect将跟随animateTo的动画参数
animateTo({ curve: curves.springMotion() }, () => {this.isPresent = false;
})// 方式二:直接控制删除或者新增组件,动画参数由TransitionEffect的animation接口配置
this.isPresent = false;
出现消失转场-转场效果
转场效果可以通过下列语法随意进行设置,支持通过点语法链式调用
// 设置多个效果 出现和消失均有转场
effect: object = TransitionEffect.OPACITY.animation({}).combine(TransitionEffect.scale({ x: 0, y: 0 }))// 组合 缩放效果.combine(TransitionEffect.rotate({ angle: 90 })) // 组合 旋转效果.combine(TransitionEffect.move(TransitionEdge.END)) // 组合 移动效果// 出现没有转场
// 消失透明度转场
effect2: object = TransitionEffect.asymmetric(TransitionEffect.IDENTITY, // 出现转场TransitionEffect.OPACITY.animation({ // 消失转场duration: 300}))
静态方法:
接口名称 | 参数类型 | 是否静态函数 | 参数描述 |
opacity | number | 是 | 设置组件转场时的透明度效果,为插入时起点和删除时终点的值。 |
translate | TranslateOptions | 是 | 设置组件转场时的平移效果,为插入时起点和删除时终点的值。 |
scale | ScaleOptions | 是 | 设置组件转场时的缩放效果,为插入时起点和删除时终点的值。 |
rotate | RotateOptions | 是 | 设置组件转场时的旋转效果,为插入时起点和删除时终点的值。 |
move | TransitionEdge | 是 | 指定组件转场时从屏幕边缘滑入和滑出的效果,本质为平移效果,为插入时起点和删除时终点的值。 |
asymmetric | appear: TransitionEffect , | 是 | 指定非对称的转场效果。 |
combine | TransitionEffect | 否 | 对TransitionEffect进行链式组合,以形成包含多种转场效果的TransitionEffect。 |
animation | AnimateParam | 否 | 指定该TransitionEffect的动画参数。 |
静态成员:
静态成员名称 | 参数描述 |
IDENTITY | 禁用转场效果。 |
OPACITY | 指定透明度为0的转场效果。即相当于TransitionEffect.opacity(0) |
SLIDE | 指定出现时从左侧滑入、消失时从右侧滑出的转场效果。即相当于TransitionEffect.asymmetric(TransitionEffect.move(TransitionEdge.START), TransitionEffect.move(TransitionEdge.END)) |
SLIDE_SWITCH | 指定出现时从右先缩小再放大侧滑入、消失时从左侧先缩小再放大滑出的转场效果。动画时长600ms,指定动画曲线曲线cubicBezierCurve(0.24f, 0.0f, 0.50f, 1.0f),最小缩放比例为0.8。 |
如果要组合多个动画效果,可以用如下的方式进行设置,之所以可以一路点下去,是因为这些设置动画的语法,设置之后返回的都是 TransitionEffect,所以继续链式调用
参考代码
@Entry
@Component
struct Page09_transitionEffect {@State isShow: boolean = false// 1. 定义转场效果effect: object = TransitionEffect.OPACITY.animation({}).combine(TransitionEffect.scale({ x: 0, y: 0 })).combine(TransitionEffect.rotate({ angle: 90 })).combine(TransitionEffect.move(TransitionEdge.END))build() {Column() {Button('切换元素').onClick(() => {this.isShow = !this.isShow})// 3. 新增或者删除组件触发转场if (this.isShow) {Text('我是文本框').fontSize(50).fontWeight(FontWeight.Bold)// 2. 添加转场效果.transition(this.effect)}// 我是底部的元素(// 元素是瞬间消失或出现的,所以这个输入框会瞬间上去或下去// 因为通过动画的方式让这一过程更为平滑,所以会出现 Text 上去了,但是消失、出现的动画还在播放// 如果要视觉效果更为美观,可以通过布局的方式让元素的出现或消失不影响布局Text('底部的文本框').fontSize(40)}.width('100%').height('100%')}
}
最后再给大家扩展一个帧动画
ImageAnimator 帧动画组件
供逐帧播放图片的能力,可以方便的控制播放状态:播放,暂停,停止..
核心用法:
ImageAnimator不是容器组件,也不需要传递参数,只需要设置属性即可
ImageAnimator().属性()
用例
@Entry
@Component
struct Page12_ImageAnimator {// 需要动画的图片// 两套动画素材// ic_animator_coin1(1-6 硬币)// ic_animator_dog1(1-4 狗狗)images: ImageFrameInfo[] = [{ src: $r('app.media.ic_animator_dog1') },{ src: $r('app.media.ic_animator_dog2') },{ src: $r('app.media.ic_animator_dog3') },{ src: $r('app.media.ic_animator_dog4') },]// 需要控制动画状态 定义状态变量 默认状态@State aniStatus: AnimationStatus = AnimationStatus.Initialbuild() {Column({ space: 10 }) {// 动画组件ImageAnimator().animatorFancy().iterations(-1)// 动画次数.duration(400)// 持续时间.height(150).images(this.images)// 动画图片.state(this.aniStatus) // 动画抓个状态// 按钮控制区域Row({ space: 20 }) {Button('启动').onClick(() => {this.aniStatus = AnimationStatus.Running // 播放})Button('暂停').onClick(() => {this.aniStatus = AnimationStatus.Paused // 暂停:停在触发的瞬间})Button('停止').onClick(() => {this.aniStatus = AnimationStatus.Stopped // 停止:直接到最后一张图})}}.width('100%').height('100%').padding(10)}// 抽取的通用属性@StylesanimatorFancy() {.width(300).backgroundColor(Color.Gray).padding(10).borderRadius(10)}
}
参数名称 | 参数类型 | 参数描述 |
images | Array<ImageFrameInfo> | 设置图片帧信息集合。 |
state | AnimationStatus | 默认为初始状态,用于控制播放状态。 |
duration | number | 单位为毫秒,默认时长为1000ms;duration为0时,不播放图片;值的改变只会在下一次循环开始时生效;当images中任意一帧图片设置了单独的duration后,该属性设置无效。 |
iterations | number | 默认播放一次,设置为-1时表示无限次播放。 |
。。。。 |
好啦,今天的内容就到这里了,这里是鸿蒙开天组~喜欢的话可以点点收藏!感谢大家~