[经验分享] 【SUBJECT技术】(MSDP)Rosen图层绘制的应用 原创

诚迈_雨哥 显示全部楼层 发表于 2024-6-3 16:44:43

一、图层绘制的若干细节

本文结合实例说明Rosen图层绘制的若干细节,以点带面,若全面了解需要深入阅读MSDP和Graphic2D子系统相关代码。

1.1. 绘制动画的数据来源

由ARKUI调用MSDP的StartDrag()接口将DragData数据信息初始化到DrawingInfo全局变量。

1.2. 从设备DPI转换图片偏移位置

获取设备的dpi,通过deviceDpi计算出缩放因子scalingValue int32_t deviceDpi = display->GetDpi();

将pixelMap的Width和Height,通过scalingValue,裁剪尺寸。 scalingValue=(1.0*deviceDpi*DEVICE_INDEPENDENT_PIXEL / BASELINE_DENSITY) / SVG_ORIGINAL_SIZE;

竖直方向增加一个adjustSize 偏移量

adjustSize = TWELVE_SIZE * GetScaling();
SetBounds(DEFAULT_POSITION_X,adjustSize,pixelMap->GetWidth(),pixelMap->GetHeight());
SetFrame(DEFAULT_POSITION_X,adjustSize,pixelMap->GetWidth(),pixelMap->GetHeight());

1.3 图层与绘制节点

1.3.1. 绘制多图层的基本步骤

  1. 创建窗口节点surfaceNode,设置背景颜色、大小、是否可见等信息;
  2. 创建根节点rootNode,设置边框长宽大小、背景颜色等信息;
  3. 初始化画布;
  4. 再分别创建nodes、filterNode、pixelMapNode、dragStyleNode、mouseIconNode节点,设置相对应的节点参数信息。

1.3.2. nodes节点存放节点信息

各节点 对应的下标常量 描述
Rosen::RSCanvasNode filterNode BACKGROUND_FILTER_INDEX 裁剪节点
Rosen::RSCanvasNode pixelMapNode PIXEL_MAP_INDEX 阴影图节点
Rosen::RSCanvasNode dragStyleNode DRAG_STYLE_INDEX 拖拽样式节点
Rosen::RSCanvasNode mouseIconNode MOUSE_ICON_INDEX 鼠标光标节点

1.3.3. rootNode节点存放节点信息

nodetree.png

其中multiSelectedNode节点是根据multiSelectedPixelMaps数量给每个像素图片创建对应的节点

1.3.4. 拖拽多张图片的层叠顺序说明

draglayer.PNG

1.4. 绘制阴影图的方法

1.4.1. SetShadow系列方法

方法 功能
SetShadowColor() 设置阴影颜色
SetShadow0ffset() 设置阴影偏移
SetShadowAlpha() 设置阴影透明度
SetShadowRadius() 设置阴影半径
SetShadowPath() 设置阴影path

1.4.2. 阴影 path 说明

Path本质上讲就是SVG的图片信息,就是如下字符串,只包含坐标尺寸部分。

<?xml version="1.0" encoding="UTF-8"?>
<svg width="300px" height="300px" viewBox="0 0 200 200">
  <rect x="10" y="10" width="40" height="40" rx="4" ry="4"
    style="stroke: gray; fill: lightgray;"/>
</svg>

用浏览器打开,显示如下:

rectangle_svg.png

1.5. 图层重叠的实现

1.5.1. 将g_drawingInfo.multiSelectedPixelMaps逐个图片添加到节点,然后保存到multiSelectedNodes

保存节点前设置相应参数,例如SetAlpha(alpha) 为设置透明度,SetRotation(degrees) 为设置旋转角度,SetForegroundColor(TRANSPARENT_COLOR_ARGB)为设置前景色

void DragDrawing::InitMultiSelectedNodes()
{
    size_t multiSelectedPixelMapsSize = g_drawingInfo.multiSelectedPixelMaps.size();
    for (size_t i = 0; i < multiSelectedPixelMapsSize; ++i) {
        std::shared_ptr<Media::PixelMap> multiSelectedPixelMap = g_drawingInfo.multiSelectedPixelMaps[i];
        std::shared_ptr<Rosen::RSCanvasNode> multiSelectedNode = Rosen::RSCanvasNode::Create();
        multiSelectedNode->SetBgImageWidth(multiSelectedPixelMap->GetWidth());
        multiSelectedNode->SetBgImageHeight(multiSelectedPixelMap->GetHeight());
        multiSelectedNode->SetBgImagePositionX(0);
        multiSelectedNode->SetBgImagePositionY(0);
        multiSelectedNode->SetForegroundColor(TRANSPARENT_COLOR_ARGB);
        auto rosenImage = std::make_shared<Rosen::RSImage>();
        rosenImage->SetPixelMap(multiSelectedPixelMap);
        rosenImage->SetImageRepeat(0);
        multiSelectedNode->SetBgImage(rosenImage);
        float alpha = DEFAULT_ALPHA;
        float degrees = DEFAULT_ANGLE;
        if (i == FIRST_PIXELMAP_INDEX) {
            alpha = FIRST_PIXELMAP_ALPHA;
            degrees = POSITIVE_ANGLE;
        } else if (i == SECOND_PIXELMAP_INDEX) {
            alpha = SECOND_PIXELMAP_ALPHA;
            degrees = NEGATIVE_ANGLE;
        }
        multiSelectedNode->SetRotation(degrees);
        multiSelectedNode->SetAlpha(alpha);
        g_drawingInfo.multiSelectedNodes.emplace_back(multiSelectedNode);
    }
}

1.5.2. 绘制前将 multiSelectedNodes 逐个添加到根节点

size_t multiSelectedNodesSize = g_drawingInfo.multiSelectedNodes.size();
for (size_t i = 0; i < multiSelectedNodesSize; ++i) {
    g_drawingInfo.rootNode->AddChild(g_drawingInfo.multiSelectedNodes[i]);
}

1.5.2. 设置好参数,用FlushImplicitTransaction()更新、重绘

Rosen::RSTransaction::FlushImplicitTransaction();

1.6. 图层错位的实现

后续目标会按照一定角度进行旋转,以形成错位效果。第一个图片为默认的角度,第二个图片根据设定的旋转角度POSITIVE_ANGLE 进行旋转,第三个图片根据NEGATIVE_ANGLE 角度进行旋转,达到层叠错位的效果。设置好属性后将节点添加到g_drawingInfo.mutilSelectedNodes中。

遍历mutilSelectedPixelMapsSize,根据索引找到FIRST_PIXELMAP_INDEX和SECOND_PIXELMAP_INDEX,设置不同的旋转角度和透明度。

constexpr float DEFAULT_ANGLE { 0.0f };    // 默认角度
constexpr float POSITIVE_ANGLE { 8.0f };   // 正向旋转角度
constexpr float NEGATIVE_ANGLE { -8.0f };  // 逆向旋转角度

1.7. 粘滞动画的实现

1.7.1. 使用延迟刷新技术,使得过程非一蹴而就

控制刷新的频率,避免过快的刷新导致拖尾效果不明显。不同层叠阴影缩略图的动画持续时间设置为不相同。在拖拽移动过程中,在前面的图片动画持续时间快于后面的图片,已达到拖尾的效果。定义动画的持续时长:

constexpr int32_t SHORT_DURATION { 55 };
constexpr int32_t LONG_DURATION { 90 };

遍历节点,设置第一个节点的动画持续效果为SHORT_DURATION,其余的动画持续效果为LONG_DURATION。

1.7.2. 使用动画缓入缓出技术,使得起止更加流畅,减少“失重”感

使用Rosen::RSNode::Animate对节点进行动画处理,参数RSAnimationTimingCurve::EASE_IN_OUT是一种动画时间曲线,用于描述动画的起始和结束阶段的速度变化。它是一种缓入缓出的曲线,意味着动画在开始和结束时速度较慢,而在中间阶段速度较快。这种时间曲线可以提供一种自然的、连续的视觉反馈,使动画看起来更加自然和流畅。在某些情况下,它还可以使动画的呈现更加平滑,从而增强用户的视觉体验。

二、参考文献

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部