鸿蒙原生系列之动画效果(转场动画)

鸿蒙原生转场动画

〇、前言

上一篇,已经完成了对动画效果中最基本的属性动画的系统性学习,这一篇,将再接再厉,对第二种动画效果:组件出现/消失转场即转场动画 ,也完成系统性的学习。

一、动画分类

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() 方法返回的节点:

相关推荐
yenggd2 小时前
企业总部-分支-门点-数据中心使用骨干网SRv6 BE互联互通整体架构配置案例
运维·网络·计算机网络·华为·架构
子榆.2 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成实战:从零构建跨平台应用
flutter·开源·harmonyos
luxy20042 小时前
HarmonyOS 5.0 WiFi连接调试工具
华为·harmonyos
夏小鱼的blog2 小时前
【HarmonyOS应用开发入门】 第二期:Stage模型与应用架构解析
harmonyos·开源鸿蒙
养猪喝咖啡4 小时前
ArkTS 文本输入组件(TextInput)详解
harmonyos
养猪喝咖啡4 小时前
HarmonyOS ArkTS 页面导航(Navigation)全面介绍
harmonyos
养猪喝咖啡4 小时前
HarmonyOS ArkTS 从 Router 到 Navigation 的迁移指南
harmonyos
养猪喝咖啡4 小时前
HarmonyOS ArkTS Stack 实战:做一个“悬浮按钮 + 遮罩弹层 + 底部菜单”的完整小项目
harmonyos
Archilect4 小时前
从几何到路径:ArkUI 下的双层容器、缩放偏移与抛掷曲线设计
harmonyos