OpenHarmony开发者论坛

标题: 【SUBJECT技术】(MSDP)Rosen图层绘制的应用 [打印本页]

作者: 诚迈_雨哥    时间: 2024-6-3 16:44
标题: 【SUBJECT技术】(MSDP)Rosen图层绘制的应用
[md]# 一、图层绘制的若干细节

本文结合实例说明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](https://forums-obs.openharmony.c ... 8k8bukyqrkwnzee.png "nodetree.png")

![](./figures/nodetree.png)
其中multiSelectedNode节点是根据multiSelectedPixelMaps数量给每个像素图片创建对应的节点

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

![draglayer.PNG](https://forums-obs.openharmony.c ... 43uaw8t61p6btbo.png "draglayer.PNG")

![](./figures/draglayer.png)

## 1.4. 绘制阴影图的方法

### 1.4.1. SetShadow系列方法

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

### 1.4.2. 阴影 path 说明

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

```xml
<?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](https://forums-obs.openharmony.c ... a7wub6163bs1agj.png "rectangle_svg.png")

![](./figures/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:ixelMap> multiSelectedPixelMap = g_drawingInfo.multiSelectedPixelMaps;
        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 逐个添加到根节点

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

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

`Rosen::RSTransaction::FlushImplicitTransaction();`

## 1.6. 图层错位的实现

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

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

```cpp
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是一种动画时间曲线,用于描述动画的起始和结束阶段的速度变化。它是一种缓入缓出的曲线,意味着动画在开始和结束时速度较慢,而在中间阶段速度较快。这种时间曲线可以提供一种自然的、连续的视觉反馈,使动画看起来更加自然和流畅。在某些情况下,它还可以使动画的呈现更加平滑,从而增强用户的视觉体验。

# 二、参考文献

* (MSDP) 探索OpenHarmony 拖拽动画的技术实现:https://forums.openharmony.cn/fo ... thread&tid=2047
* 2D 图形子系统介绍: https://gitee.com/openharmony/do ... /graphic_graphic_2d
[/md]




欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/) Powered by Discuz! X3.5