什么是组件内转场
组件内转场指的是组件在触发转场的时机所具备的动画效果。转场的时机指的是,组件元素发生变化的时候,具体为:
组件被添加
组件被删除
组件可见性发生变化-Visibility
这些场景有时候单纯的让其消失,出现,平移有时候视觉效果会比较突兀。我们可以利用组件内转场动效实现平滑的过度。
先看怎么用再分析API
图片消失组件转场案例
@Entry
@Component
//组件内转场,实现图片的出现与消失转场效果
struct TransitionEffectTest1 {
// 我们利用条件渲染语句来实现组件的出现与消失
@State isImageVisible:boolean = true
@State buttonText:string = '展示'
build() {
Column(){
Button(this.buttonText)
.onClick(()=>{
this.isImageVisible = !this.isImageVisible
this.buttonText = this.isImageVisible? '展示' : '消失'
})
if (this.isImageVisible) { //此处是条件渲染语句,isImageVisible的值发生变化,组件便可以触发消失和出现
Image($r('app.media.11073300'))
.objectFit(ImageFit.ScaleDown)
.width('100%')
.margin({top: 50})
//接下来重点,书写转场时的动效
// 这个转场配置一写,此组件的出现和消失便具备了转场效果
// 我们看到转场配置也是要出动画参数的,例如持续500毫秒,缓入缓出的效果。
// 另外转场也是可以通过combine函数来自由搭配。
.transition(
TransitionEffect.OPACITY
.combine(TransitionEffect.rotate({z: 1, angle: 180}))
.animation({duration: 500, curve: Curve.Ease})
)
}
}
.width('100%')
.height('100%')
}
}
真机效果展示:

组件转场API
我们从上文中看出,组件转场用到了一个名字叫transition的函数,这个函数是CommonMethod类中声明的一个函数。这个CommonMethod类是UI组件某顶层类, 所以所有的UI组件都可以继承下来,并调用这个方法。所有的组件都具备组件转场能力。
Transition触发时机
触发时机有两个:
当组件插入或者删除的时候, 比如条件渲染语句涉及到的条件发生了变化,或者ForEach新增或删除组件,会递归触发所有新插入或者删除组件的transition效果
当组件visibility属性,在可见与不可见之间发生改变的时候,只触发该组件的transition效果。其他组件不会触发。
关于这个函数的API,涉及的类是比较多的。 包括我们之前属性动画animation, 显式动画animateTo都用到的AnimationParam类。此处我们也会画出来!
下文中的图,既表示出来了类的关系,也表示出来了其属性的作用。我就不用文字来进行解释了!看图即可:
transition函数的位置及参数含义

TransitionEffect API分析图
TransitionEffect是组件转场动画的核心类,用于描述这个场应该怎么来转。也就是动画要是什么动画。
API如下图所示:

ainimation函数参数详解
上图中没有标注animation方法的具体参数细节。原因是这块涉及到的内容比较多,我们单独开一个图来解释

从这些类图中我们也可以大致看出来, TransitionEffect的调用特点是链式调用,其中它本身内置了几个默认的只读变量,类型也是TransitionEffect。意思很明显:直接让大家拿来用即可。里面的信息应该已经内置好了。
另外它还准备了几个设置自定义变化的接口,返回值也是TransitionEffect类型,很明显就是方便链式调用用的。
最后,它还有一个combine方法, 这个函数很明显就是连接不同的TransitionEffect使用的,由此可见,TransitionEffect是支持任意组合的形式的,比如您可以在转场的时候同时设置,平移叠加透明度变化叠加缩放的效果!
之后我们可以在代码里感受一下。
animation函数如果不进行配置会发生什么
如果您写的转场配置中,没有进行animation进行函数调用,那么转场动效会因为没有这种配置而导致不展示。默认情况下动效不展示。
但是!这里面有例外!!!如果你没有配置animation,但是有关于触发组件转场的变量变了,而这个变量变化还被写到animateTo函数中了,也就是在animateTo函数的event参数中被改变的。那么!会沿用这个动画配置!奇怪吧。这个HarmonyOS的动画比较有意思,有时间真的要研究下其实现架构和原理。
为了证明这块的区别,我又画了个图,图中表示了,代码之间的对比,与展示之间的区别:



对于组件转产动效而言,动画参数的生效,甚至可以扩展至其本身的配置之外,具体是下方的规则
动画参数生效顺序为: 本TransitionEffect指定的animation参数 > 前面的transitionEffect指定的animation参数 > 触发该组件消失的animateTo中的动画参数。
如果您根本没有配置TransitionEffect中的animation参数,并且也没有使用animateTo触发转场动画,那么该组件就不会有转场动效,直接出现或者消失。
其余还有一些我们代码中没有展示出来的注意点也需要重视一下:
如果您在写TransitionEffect时,配置的转场效果,和正常展示的效果压根没区别,那么也不会展示动效。例如一个组件平常就是不透明度为1,您配置入场动效的时候,写个 TransitionEffect.opacity(1).animation(duration: 100), 白搭不奏效的。 因为实在是没什么差别可以展示的。
TransitionEffect可通过combine函数实现多个转场效果的组合,可以为每个效果分别指定animation参数,且前一效果的animation的参数也可适用于后一效果。例如,TransitionEffect.OPACITY.animation({duration: 1000}).combine(TransitionEffect.translate({x: 100})),则时长为1000ms的动画参数对OPACITY和translate均生效。
如果在动画范围(animateTo、animation)内触发组件的上下树或可见性(Visibility)改变,而根组件没有配置transition,会给该组件加上默认透明度转场,即TransitionEffect.OPACITY,动画参数跟随所处动画环境的参数。如不需要可通过主动配置TransitionEffect.IDENTITY来禁用,使该组件直接出现或消失。
TransitionOptions API详解
如果仔细看图的话,transition其实是一个重载方法。 而TransitionOptions则是第一个重载方法的第一个参数可选类型。这个目前已经被标注为不再维护了。我们案例中也不会使用这个代码。
但是还是画了一张图,方便大家有个了解,以后万一碰到了它的使用,就比较容易理解了。

代码示例
使用不同的接口实现图片的出现消失
下图代码重点展示了
TransitionEffect.asymmetric函数的用法及展示效果。
TransitionEffect不配置animation情况下,用animateTo函数中的动画配置。
@Entry
@Component
struct TransitionEffectTest2 {
// 我们利用条件渲染语句来实现组件的出现与消失
@State isImageVisible: boolean = true
@State buttonText: string = '展示'
build() {
Column() {
Button(this.buttonText)
.onClick(() => {
//在animateTo中修改条件变量. 第二张图片的转场因为没有配置animation,而会采用此处的配置
this.getUIContext().animateTo({
duration: 500
}, () => {
this.isImageVisible = !this.isImageVisible
this.buttonText = this.isImageVisible ? '展示' : '消失'
})
})
if (this.isImageVisible) {
Image($r('app.media.11073300'))
.objectFit(ImageFit.ScaleDown)
.width('100%')
.margin({ top: 50 })//接下来重点,书写转场时的动效
.transition(
TransitionEffect.asymmetric(
TransitionEffect.OPACITY.animation({ duration: 500 })
.combine(TransitionEffect.rotate({ z: 1, angle: 180 })
.animation({ duration: 500 })), // 入场动效配置,不写animation,那就代表目前没有animation
TransitionEffect.OPACITY.animation({ delay: 1000, duration: 500 })
.combine(TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 3000 })) //离场动效配置
)
)
Image($r('app.media.11073300'))
.objectFit(ImageFit.ScaleDown)
.width('100%')
.margin({ top: 50 })
.transition(
// 这里没有写animation函数,其实默认就是没动画.但是好在onClick中写了动画,
// 会采用onclick中animateTo中的参数!!!!这点很重要!!!!一会儿专门讲讲这里面的门道.
TransitionEffect.asymmetric(
TransitionEffect.scale({ x: 0, y: 0 }),
TransitionEffect.OPACITY
)
)
}
}
.width('100%')
.height('100%')
}
}
效果展示:

父子组件同时设置Transition
下方代码为,父组件和子组件同时有转场动效的表现
@Entry
@Component
struct TransitionEffectTest3 {
// 我们利用条件渲染语句来实现组件的出现与消失
@State isImageVisible: boolean = true
@State buttonText: string = '展示'
build() {
Column() {
Button(this.buttonText)
.onClick(() => {
//在animateTo中修改条件变量. 第二张图片的转场因为没有配置animation,而会采用此处的配置
this.isImageVisible = !this.isImageVisible
this.buttonText = this.isImageVisible ? '展示' : '消失'
})
if (this.isImageVisible) {
Column(){
Image($r('app.media.11073300'))
.objectFit(ImageFit.ScaleDown)
.width('100%')
.margin({ top: 50 })//接下来重点,书写转场时的动效
.transition(
TransitionEffect.asymmetric(
TransitionEffect.OPACITY.animation({ duration: 500 })
.combine(TransitionEffect.rotate({ z: 1, angle: 180 })
.animation({ duration: 500 })), // 入场动效配置,不写animation,那就代表目前没有animation
TransitionEffect.OPACITY.animation({ delay: 1000, duration: 500 })
.combine(TransitionEffect.rotate({ z: 1, angle: 180 }).animation({ duration: 3000 })) //离场动效配置
)
)
Image($r('app.media.11073300'))
.objectFit(ImageFit.ScaleDown)
.width('100%')
.margin({ top: 50 })
.transition(
// 这里没有写animation函数,其实默认就是没动画.但是好在onClick中写了动画,
// 会采用onclick中animateTo中的参数!!!!这点很重要!!!!一会儿专门讲讲这里面的门道.
TransitionEffect.asymmetric(
TransitionEffect.scale({ x: 0, y: 0 }),
TransitionEffect.OPACITY
)
.animation({duration: 1000})
)
Button('无组件转场的button')
.width(200)
.margin({top: 30})
}
.transition(TransitionEffect.opacity(0.5).animation({duration: 3000}), (b: boolean)=>{
console.log((b? "展示" : "消失") + " 动效结束")
})
}
}
.width('100%')
.height('100%')
}
}















暂无评论内容