鸿蒙原生转场动画
- 〇、前言
- 一、动画分类
- 二、动画实现
-
- 2、转场动画
-
- 2.1、定义页面结构
- [2.2、ArkUINode.h 支持设置转场属性](#2.2、ArkUINode.h 支持设置转场属性)
- [2.3、实现 createChildImage](#2.3、实现 createChildImage)
- 2.4、真机演示
〇、前言
上一篇,已经完成了对动画效果中最基本的属性动画的系统性学习,这一篇,将再接再厉,对第二种动画效果:组件出现/消失转场即转场动画 ,也完成系统性的学习。
一、动画分类
2、转场动画
2.1、转场相关属性
让目标组件具备转场动画效果,其关键就在对目标组件设置正常的转场相关属性 。截止到发稿日期为止,鸿蒙组件所支持的相关转场属性,主要有下面几种:
1)图形变换和转场的中心点属性:NODE_TRANSFORM_CENTER
2)转场时的透明效果属性:NODE_OPACITY_TRANSITION
3)转场时的旋转效果属性:NODE_ROTATE_TRANSITION
4)转场时的缩放效果属性:NODE_SCALE_TRANSITION
5)转场时的平移效果属性:NODE_TRANSLATE_TRANSITION
6)转场时从屏幕边缘滑入和滑出的效果属性:NODE_MOVE_TRANSITION
这些转场相关属性的字段名,除了设置中心点的外,无一例外都带有TRANSITION关键词,而它们也都共同地定义在 native_node.h中:

由于每个转场相关的属性,都不是单一值结构 ,而是组合值结构,所以,仅仅知道正确的属性字段名及其设置方式,是远远还不够的,比如,我给出下面的用于设置NODE_TRANSFORM_CENTER属性的代码片段:
cpp
ArkUI_NumberValue value[] = {0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f};
ArkUI_AttributeItem item = {value, 6};
nativeModule_->setAttribute(handle_, NODE_TRANSFORM_CENTER, &item);
屏幕前的你,可知道为什么 value 数组要那样写?而value数组里面的每个元素到底代表什么意思呢? 要对这些心知肚明,就必须深入这些转场属性的值结构。下面,就让我带领你深入了解。
2.1.1、NODE_TRANSFORM_CENTER
按照顺序,先学习 NODE_TRANSFORM_CENTER 属性的值结构。
首先,要明确 NODE_TRANSFORM_CENTER 是用于设置转场的中心点 的,而一个点在屏幕空间坐标系上的描述,是用 (x, y, z) 进行刻画的,因为屏幕空间坐标系就是一个三维坐标系。
而一组坐标,即(x,y,z)实际上刻画的就是点到坐标轴之间的距离 。所以,实际上,NODE_TRANSFORM_CENTER 属性的值结构,三个成员就已经足够了,但是鸿蒙SDK为了兼顾代码的语法风格,比如设置组件的尺寸即宽高时,即可以用直接数字也可以用百分比,所以,NODE_TRANSFORM_CENTER 属性的值结构,也就扩展到了 6 个成员: {x, y, z, percentX, percentY, percentZ},后面的三个用百分比描述的,会各自覆盖前面对应的直接数值描述的坐标值。
txt
.value[0]?.f32 表示中心点X轴坐标值,单位为vp。
.value[1]?.f32 表示中心点Y轴坐标,单位为vp。
.value[2]?.f32 表示中心点Z轴坐标,单位为vp。
.value[3]?.f32 表示中心点X轴坐标的百分比位置,如0.2表示百分之20的位置,该属性覆盖value[0].f32,默认值:0.5f。
.value[4]?.f32 表示中心点Y轴坐标的百分比位置,如0.2表示百分之20的位置,该属性覆盖value[1].f32,默认值:0.5f。
.value[5]?.f32 表示中心点Z轴坐标的百分比位置,如0.2表示百分之20的位置,该属性覆盖value[2].f32,默认值:0.0f。
2.1.2、NODE_OPACITY_TRANSITION
NODE_OPACITY_TRANSITION 属性,其值结构为:{float opacity, int duration, ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed},分别表示透明度、动画时长、动画曲线、延迟播放时间(ms)、播放次数(次)、动画播放模式和动画播放速度 ,ArkUI_AnimationCurve 和 ArkUI_AnimationPlayMode 都定义在 native_type.h中,并且在上一篇的内容中都详细介绍过,这里便不赘述。
2.1.3、NODE_ROTATE_TRANSITION
NODE_ROTATE_TRANSITION 属性,其值结构为{float rotateX, float rotateY, float rotateZ, float angle, float distance, int duration, ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed},最前面的三个元素,分别表示横向旋转分量、纵向旋转分量和竖向旋转分量。
2.1.4、NODE_SCALE_TRANSITION
NODE_SCALE_TRANSITION 属性,其值结构为{float scaleX, float scaleY, float scaleZ, int duration, ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed},前三个元素分别描述横纵竖三个方向的放大倍数。
2.1.5、NODE_TRANSLATE_TRANSITION
NODE_TRANSLATE_TRANSITION 属性,其值结构为{float translateX, float translateY, float translateZ, int duration, ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed},前三个元素分别表示横纵竖三个方向各自的平移距离,单位是vp。
2.1.6、NODE_MOVE_TRANSITION
NODE_MOVE_TRANSITION 属性,其值结构为{ArkUI_TransitionEdge edge, int duration, ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed},ArkUI_TransitionEdge 表示 滑入滑出效果 ,其合法值有如下:

二、动画实现
2、转场动画
2.1、定义页面结构

演示转场动画的页面结构如上,其中最上面的两个按钮,及其之后的文本,是用 ArkTS 代码实现的,所以,在 C++ 代码中,页面结构是如下的:
cpp
bool g_transition_flag = false;
std::shared_ptr<ArkUIColumnNode> g_transition_column;
std::shared_ptr<ArkUIButtonNode> g_transition_button;
std::shared_ptr<ArkUIImageNode> g_transition_image;
std::shared_ptr<ArkUIImageNode> createChildImage()
std::shared_ptr<ArkUIBaseNode> testTransitionAnimate()
{
auto column = std::make_shared<ArkUIColumnNode>();
column -> SetPercentWidth(1.0f);
column->SetPercentHeight(1.0f);
auto button = std::make_shared<ArkUIButtonNode>();
button->SetEnable();
button->SetPercentWidth(0.4);
button->SetHeight(60);
button->SetBackgroundColor(0xFF000000);
button->SetLabel("Show");
button->RegisterNodeEvent(button->GetHandle(), NODE_ON_CLICK, 4, nullptr);
auto onShowClick = [](ArkUI_NodeEvent *event)
{
if(!event) {
return;
}
if(!g_transition_image){
g_transition_image = createChildImage();
}
if(g_transition_flag) {
g_transition_flag = false;
g_transition_button -> SetLabel("Show");
g_transition_column -> RemoveChild(g_transition_image);
showUITextCallback("转场动画", "成功隐藏图片");
}else {
g_transition_flag = true;
g_transition_button -> SetLabel("Hide");
g_transition_column -> AddChild(g_transition_image);
showUITextCallback("转场动画", "成功显示图片");
}
};
button -> RegisterNodeEventReceiver(onShowClick);
g_transition_column = column;
g_transition_button = button;
column -> AddChild(button);
return column;
}
实际上,转场动画相关的代码,在上面基本都没有出现,因为我将转场动画效果赋予了图片节点,而图片节点的实现代码,封装在createChildImage() 方法中。
2.2、ArkUINode.h 支持设置转场属性
由于转场属性是一种公共属性,所以,我将相关设置方法封装在 ArkUINode.h 文件中,而继承了该类的具体类型节点,便都有了设置转场属性的能力。
而我之所以,单独封装设置转场属性的代码,是因为领略了官方文档所贴的代码的可读性极差后,痛定思痛,决定多花点功夫优化案例:

上图便是官方文档中给出的设置转场属性的案例,可阅读性是极其的差,所以,大家也要有一种意识,那就是大公司里面的开发人员,文档撰写能力不一定就很优秀,官方文档中的代码也不一定就是最好的实践案例。
言归正传,我在 ArkUINode 类的实现代码中,补充了如下一组公共成员方法:
cpp
void SetTransformCenter(float x, float y, float z, float p_x, float p_y, float p_z){
assert(handle_);
ArkUI_NumberValue value[] = {x, y, z, p_x, p_y, p_z};
ArkUI_AttributeItem item = {value, 6};
nativeModule_->setAttribute(handle_, NODE_TRANSFORM_CENTER, &item);
}
void SetOpacityTransition(float opacity, int duration, ArkUI_AnimationCurve curve, int delay, int times,
ArkUI_AnimationPlayMode mode, float speed){
assert(handle_);
ArkUI_NumberValue value[] = {{.f32 = opacity}, {.i32 = duration}, {.i32 = curve}, {.i32 = delay},
{.i32 = times}, {.i32 = mode}, {.f32 = speed}
};
ArkUI_AttributeItem item = {value, 7};
nativeModule_->setAttribute(handle_, NODE_OPACITY_TRANSITION, &item);
}
void SetRotateTransition(float rotateX, float rotateY, float rotateZ, float angle, float distance, int duration,
ArkUI_AnimationCurve curve, int delay, int times, ArkUI_AnimationPlayMode mode, float speed){
assert(handle_);
ArkUI_NumberValue value[] = {{.f32 = rotateX}, {.f32 = rotateY}, {.f32 = rotateZ},
{.f32 = angle}, {.f32 = distance}, {.i32 = duration}, {.i32 = curve}, {.i32 = delay},
{.i32 = times}, {.i32 = mode}, {.f32 = speed}
};
ArkUI_AttributeItem item = {value, 11};
nativeModule_->setAttribute(handle_, NODE_ROTATE_TRANSITION, &item);
}
void SetScaleTransition(float scaleX, float scaleY, float scaleZ, int duration, ArkUI_AnimationCurve curve,
int delay, int times, ArkUI_AnimationPlayMode mode, float speed){
assert(handle_);
ArkUI_NumberValue value[] = {{.f32 = scaleX}, {.f32 = scaleY}, {.f32 = scaleZ},
{.i32 = duration}, {.i32 = curve}, {.i32 = delay}, {.i32 = times}, {.i32 = mode}, {.f32 = speed}
};
ArkUI_AttributeItem item = {value, 9};
nativeModule_->setAttribute(handle_, NODE_SCALE_TRANSITION, &item);
}
void SetTranslateTransition(float translateX, float translateY, float translateZ, int duration, ArkUI_AnimationCurve curve,
int delay, int times, ArkUI_AnimationPlayMode mode, float speed){
assert(handle_);
ArkUI_NumberValue value[] = {{.f32 = translateX}, {.f32 = translateY}, {.f32 = translateZ},
{.i32 = duration}, {.i32 = curve}, {.i32 = delay},
{.i32 = times}, {.i32 = mode}, {.f32 = speed}};
ArkUI_AttributeItem item = {value, 9};
nativeModule_->setAttribute(handle_, NODE_TRANSLATE_TRANSITION, &item);
}
void SetMoveTransition(ArkUI_TransitionEdge edge, int duration, ArkUI_AnimationCurve curve, int delay,
int times, ArkUI_AnimationPlayMode mode, float speed)
{
assert(handle_);
ArkUI_NumberValue value[] = {{.i32 = edge}, {.i32 = duration}, {.i32 = curve}, {.i32 = delay},
{.i32 = times}, {.i32 = mode}, {.f32 = speed}};
ArkUI_AttributeItem item = {value, 7};
nativeModule_->setAttribute(handle_, NODE_MOVE_TRANSITION, &item);
}
每个转场属性的设置方法,都充分考虑了对应属性的值结构。
2.3、实现 createChildImage
由于实现封装好转场属性的设置方法,所以,具备同官方文档中案例代码一样的转场效果的图片节点,其实现代码就变得很简洁:
cpp
std::shared_ptr<ArkUIImageNode> createChildImage()
{
auto image = std::make_shared<ArkUIImageNode>();
image -> SetPercentWidth(1.0f);
image -> SetHeight(340);
image -> SetObjectFit(ARKUI_OBJECT_FIT_CONTAIN);
image -> SetImageSrc("https://dss3.bdstatic.com/iPoZeXSm1A5BphGlnYG/skin/206.jpg?2");
image -> SetMargin(10.0f, 0.0f, 0.0f, 0.0f);
image -> SetTransformCenter(0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 0.0f);
image -> SetRotateTransition(0.0f, 0.0f, 1.0f, 360.0f, 0.0f, 500, ARKUI_CURVE_SHARP, 20, 1, ARKUI_ANIMATION_PLAY_MODE_NORMAL, 1.0);
image -> SetScaleTransition(0.0f, 0.0f, 0.0f, 500, ARKUI_CURVE_SHARP, 20, 1, ARKUI_ANIMATION_PLAY_MODE_NORMAL, 1.0);
image -> SetTranslateTransition(200.0f, 200.0f, 0.0f, 500, ARKUI_CURVE_SHARP, 20, 1, ARKUI_ANIMATION_PLAY_MODE_NORMAL, 1.0);
return image;
}
图片资源,大家可以从网上找一个自己喜欢的替换。这里,为了支持图片资源的动态设置,将之前已实现的 SetImageSrc 方法进行了更新,并新增了一个 SetObjectFit 方法:
cpp
void SetImageSrc(const char* src = "resource:///logo.png"){
assert(handle_);
ArkUI_AttributeItem item = {.string = src};
nativeModule_ -> setAttribute(handle_, NODE_IMAGE_SRC, &item);
}
void SetObjectFit(ArkUI_ObjectFit objectFit){
assert(handle_);
ArkUI_NumberValue value[] = {{.i32 = objectFit}};
ArkUI_AttributeItem item = {value, 1};
nativeModule_ -> setAttribute(handle_, NODE_IMAGE_OBJECT_FIT, &item);
}
所以,屏幕前的你,也要记得将自己工程里面 ArkUIImageNode 类的实现代码进行更新。
2.4、真机演示
在进行真机部署和演示前,记得将 NativeEntry.cpp 中 CreateNativeRoot 方法引用的根节点,替换为 testTransitionAnimate() 方法返回的节点:
