OpenHarmony实战:拖拽动画的技术实现

拖拽动画特别指服务端在拖拽各环节发起的动画效果,功能将集中在拖拽框架 MSDP 子系统 DragDrawing 中实现。

Graphic-2D 库[^graphic_2d]提供了强大的图片绘制、动画增强服务,该子系统调用了其对外服务的能力。

1. DrawingInfo 绘图信息

绘图数据来源拖拽数据 DragData,包括阴影缩略图 ShadowInfo 以及绘制各种动画需要的节点信息

struct DrawingInfo {
    std::atomic_bool isRunning { false };                       // 发起拖拽时为true,拖拽完成后为false
    std::atomic_bool isPreviousDefaultStyle { false };          // 前一个默认拖拽光标状态
    std::atomic_bool isCurrentDefaultStyle { false };           // 是否采用默认拖拽光标风格
    bool isInitUiDirector { true };                             // Rosen::RSUIDirector::Create() 系统仅被create一次标志
    bool isExistScalingVallue { false };                        // 缩放系数是否存在标志,不存在需计算, 判断 scalingValue 的有效性
    int32_t sourceType { -1 };                                  // 输入设备源类型(鼠标、触屏等)
    int32_t currentDragNum { -1 };                              // 拖拽的对象个数
    DragCursorStyle currentStyle { DragCursorStyle::DEFAULT };  // 设置默认拖拽光标,和isCurrentDefaultStyle状态联合使用,此时状态为 true
    int32_t displayId { -1 };                                   // 显示的应用ID
    int32_t pixelMapX { -1 };                                   // 图片相对于画布边缘x向距离,在文本编辑器内偏移负的一半宽度
    int32_t pixelMapY { -1 };                                   // 图片相对于画布边缘y向距离
    int32_t displayX { -1 };                                    // 动态的显示位置 x坐标
    int32_t displayY { -1 };                                    // 动态的显示位置 y坐标
    int32_t mouseWidth { 0 };                                   // 鼠标圆环、箭头图形的宽度,由pixelMap->GetWidth()获取
    int32_t mouseHeight { 0 };                                  // 鼠标圆环、箭头图形的高度,由pixelMap->GetHeight()获取
    int32_t rootNodeWidth { -1 };                               // 没有用到
    int32_t rootNodeHeight { -1 };                              // 没有用到
    float scalingValue { 0.0 };                                             // scalingValue = (1.0 * deviceDpi * DEVICE_INDEPENDENT_PIXEL / BASELINE_DENSITY) / SVG_ORIGINAL_SIZE;
    std::vector<std::shared_ptr<Rosen::RSCanvasNode>> nodes;                // 当前画图节点,包括  BACKGROUND_FILTER_INDEX { 0 }; PIXEL_MAP_INDEX { 1 }; DRAG_STYLE_INDEX { 2 };MOUSE_ICON_INDEX { 3 };
    std::vector<std::shared_ptr<Rosen::RSCanvasNode>> mutilSelectedNodes;   // 多选节点,和 mutilSelectedPixelMaps 一起使用
    std::shared_ptr<Rosen::RSNode> rootNode { nullptr };                    // 根节点
    std::shared_ptr<Rosen::RSNode> parentNode { nullptr };                  // 父节点
    std::shared_ptr<Rosen::RSSurfaceNode> surfaceNode { nullptr };          // 界面节点
    std::vector<std::shared_ptr<Media::PixelMap>> mutilSelectedPixelMaps;   // 多选图片,和 mutilSelectedNodes 一起使用
    std::shared_ptr<Media::PixelMap> pixelMap { nullptr };                  // 存放的是 ShadowInfo,和 pixelMapX,pixelMapY一起使用
    std::shared_ptr<Media::PixelMap> stylePixelMap { nullptr };             // 有效的拖拽光标,来自svg 文件的拷贝、移动、禁止图标,此isCurrentDefaultStyle状态为false
    std::string extraInfo;                                                  // 跨设备拖拽的附加参数,包括拖拽类型,模糊,圆角半径和缩放系数,来自json文件
    std::string filterInfo;
};stylePixelMap

2. 节点 Node 相关功能描述

节点描述

1. g_drawingInfo.nodes[4]:  
g_drawingInfo.nodes[DRAG_STYLE_INDEX];          // 0: dragStyleNode  
g_drawingInfo.nodes[BACKGROUND_FILTER_INDEX];   // 1: filterNode  
g_drawingInfo.nodes[MOUSE_ICON_INDEX];          // 2: mouseIconNode  
g_drawingInfo.nodes[PIXEL_MAP_INDEX];           // 3: shadowNode  
2. g_drawingInfo.surfaceNode                    // Rosen::RSSurfaceNode::Create(surfaceNodeConfig, surfaceNodeType);
3. g_drawingInfo.rootNode
4. g_drawingInfo.parentNode
5. g_drawingInfo.mutilSelectedNodes.emplace_back(mutilSelectedNode[i]); // 多个

渲染树结构图

3. 拖拽动画接口类定义

涉及动画的地方为开始拖拽,拖拽过程中,拖拽成功,拖拽失败。

class IDragAnimation {
public:
    IDragAnimation() = default;
    virtual ~IDragAnimation() = default;
    virtual void OnStartDrag(const DragAnimationData &dragAnimationData,
        std::shared_ptr<Rosen::RSCanvasNode> shadowNode,
        std::shared_ptr<Rosen::RSCanvasNode> styleNode) = 0;
    virtual void OnDragStyle(std::shared_ptr<Rosen::RSCanvasNode> styleNode,
        std::shared_ptr<Media::PixelMap> stylePixelMap) = 0;
    virtual void OnStopDragSuccess(std::shared_ptr<Rosen::RSCanvasNode> shadowNode,
        std::shared_ptr<Rosen::RSCanvasNode> styleNode) = 0;
    virtual void OnStopDragFail(std::shared_ptr<Rosen::RSSurfaceNode> surfaceNode,
        std::shared_ptr<Rosen::RSNode> rootNode) = 0;
};

. 实现动画的典型流程

CheckNodesValid 节点有效性检查,拖拽框架仅针对鼠标、触屏两种设备,如果是鼠标则有 4 个节点,如果是触屏则只有 3 个节点,它不包含鼠标样式节点。

给动画的工作流程大致相同,以下分别用拖拽开始、拖拽成功动画为例说明:

拖拽开始动画流程

拖拽成功动画流程

5. 关于四个修改器的使用说明

a. class DrawSVGModifier : public Rosen::RSContentStyleModifier

是关于 dragStyleNode 节点的绘制,包含图片有移动、复制、禁止等 SVG 图。

索引下标为 DRAG_STYLE_INDEX,std::shared_ptrRosen::RSCanvasNode dragStyleNode = g_drawingInfo.nodes[DRAG_STYLE_INDEX];

b. class DrawPixelMapModifier : public Rosen::RSContentStyleModifier

是关于 pixelMapNode 节点的绘制,是指 ShadowInfo 中包含的阴影图。

索引下标为 PIXEL_MAP_INDEX,std::shared_ptrRosen::RSCanvasNode pixelMapNode = g_drawingInfo.nodes[PIXEL_MAP_INDEX];

c. class DrawMouseIconModifier : public Rosen::RSContentStyleModifier

是关于 mouseIconNode 节点的绘制,是指鼠标箭头、圆环图,显示图片前会修改图片大小和填充颜色。

索引下标为 MOUSE_ICON_INDEX,std::shared_ptrRosen::RSCanvasNode mouseIconNode = g_drawingInfo.nodes[MOUSE_ICON_INDEX];

d. class DrawDynamicEffectModifier : public Rosen::RSContentStyleModifier

拖拽结束动画和多选动画中的节点透明度、缩放系数,存在一组开始参数和结束参数,在播放动画时会被调用。

该修改器添加在父节点上。

    drawDynamicEffectModifier_ = std::make_shared<DrawDynamicEffectModifier>();
    g_drawingInfo.rootNode->AddModifier(drawDynamicEffectModifier_);

6. 各个环节动画的差异性说明

Function Animate Paramenters libdrag_drop_ext.z.so implement
OnStartDrag None OnStartDragExt
OnDragStyle dragStyleNode->AddModifier(drawSVGModifier_) OnDragStyleExt
OnStopDragSuccess BEGIN_ALPHA BEGIN_SCALE END_ALPHA END_SCALE_SUCCESS SUCCESS_ANIMATION_DURATION OnStopDragSuccessExt
OnStopDragFail BEGIN_ALPHA BEGIN_SCALE END_ALPHA END_SCALE_FAIL SUCCESS_ANIMATION_DURATION OnStopDragFailExt

7. 动画中时间、位置曲线名词解释

RSAnimationTimingCurve 时间速度曲线参数描述

描述 速度曲线
linear 动画从头到尾的速度是相同的。
ease 默认。动画以低速开始,然后加快,在结束前变慢。
ease-in 动画以低速开始。
ease-out 动画以低速结束。
ease-in-out 动画以低速开始和结束。

动画效果如下[^ease_timegif]:

AnimationCurve 位置曲线参数描述

多点位置的平滑曲线算法繁多,且复杂,一般有 cubic-bezier,spring,interpolating-spring,responsive-spring-motion,steps 使用较多的是 cubic-bezier 和 spring 算法。该子系统直接调用 Graphic-2d 库中位置曲线,至于内部实现不再赘述。

位置曲线效果如下:

Duration 动画时长

我们设定动画的持续时间在 300-400ms。具体的运动时长视具体动画而定,时长并不一成不变。

动画时长效果如下:

8. 现将 OpenHarmony 图形栈的分层说明如下:

  • 接口层:提供图形的 Native API 能力,包括:WebGL、Native Drawing 的绘制能力、OpenGL 指令级的绘制能力支撑等。
  • 框架层:分为 Render Service、Drawing、Animation、Effect、显示与内存管理五个模块。
模块 能力描述
Render Servicel (渲染服务) 提供 UI 框架的绘制能力,其核心职责是将 ArkUI 的控件描述转换成绘制树信息,根据对应的渲染策略,进行最佳路径渲染。同时,负责多窗口流畅和空间态下 UI 共享的核心底层机制。
Drawing (绘制) 提供图形子系统内部的标准化接口,主要完成 2D 渲染、3D 渲染和渲染引擎的管理等基本功能。
Animation (动画) 提供动画引擎的相关能力。
Effect (效果) 主要完成图片效果、渲染特效等效果处理的能力,包括:多效果的串联、并联处理,在布局时加入渲染特效、控件交互特效等相关能力。
显示与内存管理 此模块是图形栈与硬件解耦的主要模块,主要定义了 OpenHarmony 显示与内存管理的能力,其定义的南向 HDI 接口需要让不同的 OEM 厂商完成对 OpenHarmony 图形栈的适配.
  • 引擎层:包括 2D 图形库和 3D 图形引擎两个模块。2D 图形库提供 2D 图形绘制底层 API,支持图形绘制与文本绘制底层能力。3D 图形引擎能力尚在构建中。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony **多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)**技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

鸿蒙(HarmonyOS NEXT)最新学习路线

  • HarmonOS基础技能
  • HarmonOS就业必备技能
  • HarmonOS多媒体技术
  • 鸿蒙NaPi组件进阶
  • HarmonOS高级技能
  • 初识HarmonOS内核
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频 ,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类...等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .......

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ......

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ......

获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料****

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。

相关推荐
也无晴也无风雨33 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
SRC_BLUE_1735 分钟前
SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based
android·网络安全·adb·less
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
无尽的大道4 小时前
Android打包流程图
android
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
镭封5 小时前
android studio 配置过程
android·ide·android studio
夜雨星辰4875 小时前
Android Studio 学习——整体框架和概念
android·学习·android studio