跳转至

在 SOUI 中使用 SVG

概述

在高分屏时代,传统位图资源(PNG、BMP 等)已难以满足现代 UI 开发对多分辨率适配、资源体积和视觉效果的要求。SVG(Scalable Vector Graphics,可缩放矢量图形)作为一种基于 XML 的矢量图形格式,凭借无损缩放、体积小、易编辑等优势,被广泛应用于各类 UI 开发中。

SOUI 框架通过集成轻量级 SVG 解析引擎,并与自身的 RenderTarget 渲染系统深度结合,为开发者提供了一套高效、灵活的 SVG 资源解决方案。

SVG 支持方案:技术实现

1. 轻量级 SVG 解码引擎

SOUI 采用 NanoSVG 库作为 SVG 解析引擎,这是一个专为嵌入式系统和游戏开发设计的轻量级库:

技术特点:

  • 轻量级:NanoSVG 代码量小,集成成本低
  • 高性能:解析速度快,内存占用小
  • 跨平台:支持 Windows、Linux 等平台

SOUI 的扩展改进:

  • Text 标签支持:在原版 NanoSVG 基础上增加了 <text> 标签支持,使 SVG 可以包含文本元素
  • 渐变参数修复:修复了渐变参数传递的问题,确保线性渐变和径向渐变能够正确渲染
  • 属性兼容性:解决了 SVG 属性大小写区分的问题,提高了兼容性

2. 与 RenderTarget 的深度结合

SOUI 的核心特色在于将 SVG 与自身的 RenderTarget 渲染系统进行了有机结合,无需引入额外的渲染库,完全基于 SOUI 自身的渲染系统:

// IRenderTarget 接口中扩展的 DrawSVG 方法
STDMETHOD_(HRESULT, DrawSVG)(THIS_ 
    ISvgObj * pSvg,           // SVG对象
    LPCRECT pRect,            // 目标绘制区域
    LPCRECT prcSrc = NULL,    // 源SVG区域(可选)
    BYTE byAlpha = 0xFF       // 透明度(0-255)
) PURE;

技术原理: 利用 SOUI 现有的矢量图形渲染能力,将 SVG 的路径、填充、描边等元素直接转换为 RenderTarget 可处理的绘制命令,避免了"先光栅化后渲染"的传统方式,完整保留了 SVG 的矢量优势。

3. 九宫格绘制支持

SOUI 为 SVG 实现了原生的九宫格绘制功能,这是 UI 开发中极为常用的特性:

实现原理: 将 SVG 图像分割为 9 个部分(4 个角、4 条边、1 个中心),分别调用 DrawSVG 绘制到目标区域的对应位置,保持边角不变形,边框和背景独立拉伸。

适用场景: - 按钮背景(圆角保持不变) - 窗口边框(边角弧度保持) - 输入框、列表项等需要拉伸的 UI 元素

4. 智能 SVG 加载机制

SOUI 的 SVG 加载机制设计简洁,支持两种识别方式:

  1. 资源类型前缀识别:通过 SVG: 前缀识别,例如 svg:btn_play
  2. 文件扩展名识别:自动识别 .svg 文件扩展名

加载逻辑(简化版):

void SSkinImgList::LoadSrcImage() const
{
    if (m_strSrc.IsEmpty()) return;

    SStringWList list;
    SplitString(m_strSrc, L':', list);
    if (list.GetCount() == 1) {
        list.InsertAt(0, L"file");
    }
    list[0].MakeLower();
    list[1].MakeLower();

    // 识别SVG资源
    if (list[0] == L"svg" || 
        (list[0] == L"file" && list[1].EndsWith(L"svg") == 0))
    {
        m_pSvg.Attach(CreateSvgFromResId(S_CW2T(m_strSrc)));
    }
    else
    {
        m_pImg.Attach(LOADIMAGE2(m_strSrc));
    }
}

5. 编译控制开关

SOUI 的 CMake 构建系统提供了 SOUI_ENABLE_SVG 编译开关,让开发者可以根据项目需求灵活控制:

option(SOUI_ENABLE_SVG "Enable SVG support" ON)
  • ON:启用 SVG 支持(默认)
  • OFF:禁用 SVG 支持,减小最终可执行文件体积

SVG vs PNG:技术对比

特性 PNG 方案 SVG 方案
分辨率依赖 高 DPI 设备需准备多套资源,增加体积 一次设计,处处适用,无需多套资源
内存占用 每个分辨率独立位图数据,占用大 只需加载一次矢量数据,占用小
文件体积 多状态多尺寸时体积迅速膨胀 简单图形比 PNG 小数倍至数十倍
缩放效果 非整数倍缩放模糊或有锯齿 无损缩放,任意分辨率保持清晰
动态生成 难以通过程序动态生成或修改 文本格式,易于程序或 AI 生成修改
缩放性能 非 1:1 绘制需插值,性能损失大 无论如何缩放性能稳定
渲染效率 九宫格需像素处理,开销大 矢量特性九宫格场景表现出色
可编辑性 二进制格式,编辑困难 文本格式,易于编辑和修改

SVG 资源的组织方式

参考 xmusic 项目的实际结构,建议按以下方式组织 SVG 资源:

uires/
├── uires.idx            # 资源索引文件
├── svg/                 # SVG资源目录
│   ├── btn_play.svg
│   ├── btn_pause.svg
│   ├── btn_close.svg
│   ├── search_box_bg.svg
│   ├── progress_track.svg
│   ├── volume_filled.svg
│   └── ...
├── values/
│   └── skin.xml         # 皮肤定义文件
└── ...

在 XML 中使用 SVG

1. imglist 与 SVG:多状态图标皮肤

imglist 是使用 SVG 最常见的方式,适用于按钮、图标等需要多种状态的场景。

来自 xmusic 项目的实际例子(skin.xml):

<skin>
    <!-- 播放按钮 - 4种状态: normal, hover, pressed, disabled -->
    <imglist name="skin_play_btn" src="svg:btn_play" states="4"/>

    <!-- 暂停按钮 - 4种状态 -->
    <imglist name="skin_pause_btn" src="svg:btn_pause" states="4"/>

    <!-- 停止按钮 - 4种状态 -->
    <imglist name="skin_stop_btn" src="svg:btn_stop" states="4"/>

    <!-- 上一曲/下一曲按钮 -->
    <imglist name="skin_prev_btn" src="svg:btn_prev" states="4"/>
    <imglist name="skin_next_btn" src="svg:btn_next" states="4"/>

    <!-- 窗口控制按钮 -->
    <imglist name="skin_btn_minimize" src="svg:btn_minimize" states="4"/>
    <imglist name="skin_btn_maximize" src="svg:btn_maximize" states="4"/>
    <imglist name="skin_btn_restore" src="svg:btn_restore" states="4"/>
    <imglist name="skin_btn_close" src="svg:btn_close" states="4"/>

    <!-- 功能按钮 -->
    <imglist name="skin_btn_playlist" src="svg:btn_playlist" states="4"/>
    <imglist name="skin_btn_eq" src="svg:btn_eq" states="4"/>

    <!-- 进度条相关 -->
    <imglist name="skin_progress_track" src="svg:progress_track"/>
    <imglist name="skin_progress_filled" src="svg:progress_filled"/>
    <imglist name="skin_progress_thumb" src="svg:progress_thumb" states="4"/>

    <!-- 收藏图标 - 2种状态: 未收藏, 已收藏 -->
    <imglist name="skin_favorite" src="svg:icon_favorite" states="2"/>

    <!-- 音量图标 - 3种状态: 静音, 小音量, 大音量 -->
    <imglist name="skin_volume_icon" src="svg:icon_volume" states="3"/>

    <!-- 批量转换动画 - 10帧动画 -->
    <imglist name="skin_icon_converting_anim" src="svg:icon_converting" states="10"/>
</skin>

对应的 SVG 文件结构(btn_play.svg):

<?xml version="1.0" encoding="UTF-8"?>
<!-- 播放按钮 - 4种状态水平排列:每 50px 为一个状态 -->
<svg width="200" height="50" viewBox="0 0 200 50" 
     fill="none" xmlns="http://www.w3.org/2000/svg">
  <!-- State 1: Normal (0-50px) - 红色圆形背景 + 白色播放图标 -->
  <g transform="translate(0, 0)">
    <circle cx="25" cy="25" r="25" fill="#e60026"/>
    <path d="M20 17v16l12-8z" fill="#ffffff"/>
  </g>

  <!-- State 2: Hover (50-100px) - 亮红色圆形背景 -->
  <g transform="translate(50, 0)">
    <circle cx="25" cy="25" r="25" fill="#ff1744"/>
    <path d="M20 17v16l12-8z" fill="#ffffff"/>
  </g>

  <!-- State 3: Pushed (100-150px) - 深红色圆形背景 -->
  <g transform="translate(100, 0)">
    <circle cx="25" cy="25" r="25" fill="#cc0022"/>
    <path d="M20 17v16l12-8z" fill="#ffffff"/>
  </g>

  <!-- State 4: Disabled (150-200px) - 灰色圆形背景 -->
  <g transform="translate(150, 0)">
    <circle cx="25" cy="25" r="25" fill="#666666"/>
    <path d="M20 17v16l12-8z" fill="#999999"/>
  </g>
</svg>

2. imgframe 与 SVG:九宫格拉伸皮肤

imgframe 用于需要九宫格拉伸的场景,如按钮背景、输入框边框、菜单边框等。

来自 xmusic 项目的实际例子:

<skin>
    <!-- 搜索框背景 - 左右各10px保持不变,中间拉伸 -->
    <imgframe name="skin_search_box_bg" 
              src="svg:search_box_bg" 
              margin="10,0,10,0"/>

    <!-- 音量滑块轨道 - 九宫格拉伸 -->
    <imgframe name="skin_volume_track" 
              src="svg:volume_track" 
              margin="5,0,5,0"/>
    <imgframe name="skin_volume_filled" 
              src="svg:volume_filled" 
              margin="5,0,5,0"/>

    <!-- 普通按钮 - 4种状态,九宫格拉伸 -->
    <imgframe name="skin_btn_normal" 
              src="svg:btn_normal" 
              margin="8,5,8,5" 
              states="4"/>

    <!-- 主按钮(强调色) - 4种状态 -->
    <imgframe name="skin_btn_primary" 
              src="svg:btn_primary" 
              margin="8,5,8,5" 
              states="4"/>

    <!-- 播放列表项背景 - 4种状态 -->
    <imgframe name="skin_playlist_item_bg" 
              src="svg:playlist_item_bg" 
              margin="10,0,10,0" 
              states="4"/>

    <!-- 输入框边框 - 2种状态: normal, focus -->
    <imgframe name="skin_edit_border" 
              src="svg:border_edit" 
              margin="3,3,3,3" 
              states="2"/>

    <!-- 托盘菜单背景 - 圆角边框 -->
    <imgframe name="skin_bg_tray_menu" 
              src="svg:bg_tray_menu" 
              margin="12,12,12,12"/>

    <!-- 批量转换进度条 - 九宫格拉伸 -->
    <imgframe name="skin_progress_batch_track" 
              src="svg:progress_batch_track" 
              margin="10,0,10,0"/>
    <imgframe name="skin_progress_batch_filled" 
              src="svg:progress_batch_filled" 
              margin="10,0,10,0"/>

    <!-- 歌词API列表项背景 - 4种状态 -->
    <imgframe name="skin_lyrics_api_item_bg" 
              src="svg:bg_lyrics_api_item" 
              margin="8,8,8,8" 
              states="4"/>
</skin>

对应的 SVG 文件结构(search_box_bg.svg):

<?xml version="1.0" encoding="UTF-8"?>
<!-- 搜索框背景 - 圆角矩形,左右圆角通过margin保持不变 -->
<svg xmlns="http://www.w3.org/2000/svg" 
     width="100" height="36" viewBox="0 0 100 36">
    <rect x="0" y="0" width="100" height="36" 
          fill="#2a2a2a" 
          stroke="#3a3a3a" 
          stroke-width="1" 
          rx="18" ry="18"/>
</svg>

3. vscrollbar 与 SVG:滚动条皮肤

滚动条也可以使用 SVG 实现:

<skin>
    <!-- 自定义列表滚动条 - 4种状态,margin控制九宫格 -->
    <vscrollbar name="skin_vscrollbar_lv" 
                src="svg:scrollbar_lv" 
                states="4" 
                margin="6"/>
</skin>

4. 在布局中使用 SVG 皮肤

定义好皮肤后,在布局 XML 中通过 skin 属性引用:

<!-- 使用 SVG 按钮皮肤 -->
<button skin="skin_play_btn" width="50" height="50" name="btn_play"/>
<button skin="skin_pause_btn" width="50" height="50" name="btn_pause"/>

<!-- 使用 SVG 输入框边框 -->
<edit skin="skin_edit_border" 
      background="#00000000" 
      width="200" height="32"/>

<!-- 使用 SVG 搜索框背景 -->
<window skin="skin_search_box_bg" width="300" height="36">
    <edit background="#00000000" padding="10,0,36,0"/>
    <button skin="skin_btn_search" 
            pos="-36,0,-0,-0" width="36" height="36"/>
</window>

<!-- 使用 SVG 进度条 -->
<progress pos="10,0,-10,30" 
          skinTrack="skin_progress_track" 
          skinSeek="skin_progress_filled" 
          skinThumb="skin_progress_thumb"/>

<!-- 使用 SVG 音量滑块 -->
<slider pos="10,0,-10,30" 
        skinChannel="skin_volume_track" 
        skinThumb="skin_volume_thumb"/>

在 C++ 代码中使用 SVG

1. 从皮肤对象获取 SVG 并绘制

void CMyControl::OnPaint(IRenderTarget *pRT)
{
    // 获取皮肤对象
    SSkinObjBase *pSkin = GetSkin();
    if (!pSkin) return;

    // 获取SVG对象
    ISvgObj* pSvg = pSkin->GetSvg();
    if (pSvg)
    {
        // 绘制整个SVG到目标区域
        CRect rcDest = GetClientRect();
        pRT->DrawSVG(pSvg, &rcDest, NULL, 255);

        // 绘制SVG的部分区域(源裁剪)
        CRect rcSrc(10, 10, 50, 50);  // 取SVG的(10,10)到(50,50)区域
        CRect rcDest2(0, 0, 40, 40);  // 绘制到40x40的区域
        pRT->DrawSVG(pSvg, &rcDest2, &rcSrc, 200);  // 带透明度
    }
}

2. 直接从资源加载 SVG

#include <svg/SvgObject.h>

void DrawSvgFromResource(IRenderTarget* pRT, const CRect& rc)
{
    // 方式1:通过资源前缀加载
    ISvgObj* pSvg1 = CreateSvgFromResId(_T("SVG:btn_play"));

    // 方式2:通过文件路径加载
    ISvgObj* pSvg2 = CreateSvgFromFile(_T("svg/btn_play.svg"));

    if (pSvg1)
    {
        pRT->DrawSVG(pSvg1, &rc);
        pSvg1->Release();
    }
}

3. 自定义控件中使用 SVG 作为状态绘制

class SMyButton : public SButton
{
protected:
    void OnPaint(IRenderTarget *pRT)
    {
        SSkinObjBase *pSkin = GetSkin();
        if (pSkin && pSkin->GetSvg())
        {
            // 根据当前状态选择SVG的区域
            int nState = GetState();  // 0=normal, 1=hover, 2=pressed, 3=disabled
            SIZE szSvg = pSkin->GetSkinSize();
            int nStates = ((SSkinImgList*)pSkin)->GetStates();
            int cxItem = szSvg.cx / nStates;

            CRect rcSrc(nState * cxItem, 0, (nState + 1) * cxItem, szSvg.cy);
            CRect rcDest = GetClientRect();

            pRT->DrawSVG(pSkin->GetSvg(), &rcDest, &rcSrc);
        }
        else
        {
            __super::OnPaint(pRT);
        }
    }
};

SVG 设计规范与最佳实践

1. 多状态 SVG 设计规范

设计包含多状态的 SVG 时,应遵循以下规范:

状态数量 排列方式 典型应用
2 状态 水平 2 列 收藏/取消收藏、开关等
3 状态 水平 3 列 音量图标(静音/低/高)等
4 状态 水平 4 列 最常用:按钮的 normal/hover/pressed/disabled
6-10 状态 水平 N 列 复杂动画、帧动画等

示例:4 状态按钮 SVG 布局

Width = 4 × 单状态宽度
┌─────────┬─────────┬─────────┬─────────┐
│ Normal  │  Hover  │ Pressed │Disabled │
│  0~W/4  │ W/4~W/2 │ W/2~3W/4│ 3W/4~W  │
└─────────┴─────────┴─────────┴─────────┘

2. 九宫格 SVG 设计规范

对于需要拉伸的 SVG(按钮背景、边框等),需要合理设计 margin:

margin="左,上,右,下" 或 margin="统一值"

推荐设计:

元素类型 推荐 margin 说明
圆角按钮 8,5,8,5 左右 8px 保持圆角,上下 5px
输入框 3,3,3,3 四边各 3px 保持边框
搜索框(胶囊形) 18,0,18,0 左右保持半圆形状
菜单边框 8,8,8,8 四角 8px 圆角
进度条轨道 10,0,10,0 左右保持圆角,中间拉伸

3. 颜色设计建议

  • 使用语义化颜色命名,便于主题切换
  • 状态颜色保持一致的亮度差(如 hover 比 normal 亮 10-15%)
  • disabled 状态统一使用灰色系
  • 主色调、强调色保持一致性

xmusic 项目的颜色方案示例:

<!-- values/color.xml -->
<color>
    <item name="color_primary">#e60026</item>       <!-- 主色:红色 -->
    <item name="color_primary_light">#ff1744</item>   <!-- 主色亮色(hover) -->
    <item name="color_primary_dark">#cc0022</item>    <!-- 主色暗色(pressed) -->
    <item name="color_disabled">#666666</item>        <!-- 禁用色 -->
    <item name="color_bg_dark">#2a2a2a</item>         <!-- 暗色背景 -->
    <item name="color_border">#3a3a3a</item>          <!-- 边框色 -->
</color>

4. SVG 文件优化建议

  1. 简化路径:使用简化工具优化 SVG 路径数据,减小文件体积
  2. 移除冗余属性:移除编辑器生成的无用属性(如 inkscape:sodipodi: 前缀)
  3. 统一 viewBox:保持合理的 viewBox 尺寸,避免过大数据
  4. 避免嵌套过深:减少不必要的 <g> 嵌套层级
  5. 使用十六进制颜色:优先使用 #RRGGBB 格式,兼容性更好

5. 常见 SVG 模板

圆角按钮背景(4 状态):

<?xml version="1.0" encoding="UTF-8"?>
<svg width="400" height="40" viewBox="0 0 400 40" xmlns="http://www.w3.org/2000/svg">
  <!-- Normal: 100x40 -->
  <g transform="translate(0,0)">
    <rect x="1" y="1" width="98" height="38" rx="5" ry="5" 
          fill="#e60026" stroke="#cc0022" stroke-width="1"/>
  </g>
  <!-- Hover: 100x40 -->
  <g transform="translate(100,0)">
    <rect x="1" y="1" width="98" height="38" rx="5" ry="5" 
          fill="#ff1744" stroke="#e60026" stroke-width="1"/>
  </g>
  <!-- Pressed: 100x40 -->
  <g transform="translate(200,0)">
    <rect x="1" y="1" width="98" height="38" rx="5" ry="5" 
          fill="#cc0022" stroke="#aa0011" stroke-width="1"/>
  </g>
  <!-- Disabled: 100x40 -->
  <g transform="translate(300,0)">
    <rect x="1" y="1" width="98" height="38" rx="5" ry="5" 
          fill="#666666" stroke="#555555" stroke-width="1"/>
  </g>
</svg>

图标按钮(4 状态,带透明背景):

<?xml version="1.0" encoding="UTF-8"?>
<svg width="160" height="40" viewBox="0 0 160 40" xmlns="http://www.w3.org/2000/svg">
  <!-- Normal: 深色图标 -->
  <g transform="translate(0,0)">
    <path d="M20 10 L30 20 L20 30 M10 20 L28 20" 
          fill="none" stroke="#333333" stroke-width="2" stroke-linecap="round"/>
  </g>
  <!-- Hover: 主色图标 -->
  <g transform="translate(40,0)">
    <path d="M60 10 L70 20 L60 30 M50 20 L68 20" 
          fill="none" stroke="#e60026" stroke-width="2" stroke-linecap="round"/>
  </g>
  <!-- Pressed: 深色主色 -->
  <g transform="translate(80,0)">
    <path d="M100 10 L110 20 L100 30 M90 20 L108 20" 
          fill="none" stroke="#cc0022" stroke-width="2" stroke-linecap="round"/>
  </g>
  <!-- Disabled: 灰色 -->
  <g transform="translate(120,0)">
    <path d="M140 10 L150 20 L140 30 M130 20 L148 20" 
          fill="none" stroke="#999999" stroke-width="2" stroke-linecap="round"/>
  </g>
</svg>

AI 辅助 SVG 生成

SVG 的文本格式特性使其成为 AI 辅助 UI 开发的理想选择。

典型工作流

步骤 1:准备设计规范

请生成一套音乐播放器的 SVG 图标资源,要求:
- 颜色方案:主色 #e60026,暗色背景 #2a2a2a,文字 #ffffff
- 每个按钮 4 种状态水平排列(normal/hover/pressed/disabled)
- 单状态尺寸 40x40px,4 状态总宽度 160px
- 包含图标:播放、暂停、停止、上一曲、下一曲、播放列表、设置、最小化、最大化、关闭

步骤 2:AI 生成 SVG 代码

AI 会根据要求直接输出可使用的 SVG 文件内容。

步骤 3:集成到 SOUI

将生成的 SVG 文件放入 uires/svg/ 目录,在 skin.xml 中引用:

<imglist name="skin_play_btn" src="svg:btn_play" states="4"/>

AI 生成 SVG 的优势

  1. 格式友好:基于 XML 的文本格式,AI 可以直接生成和修改
  2. 批量处理:根据设计规范批量生成风格一致的 UI 元素
  3. 快速迭代:几秒钟内生成多种设计方案,加速开发流程
  4. 个性化定制:根据用户需求生成独特的 UI 元素

常见问题

Q1:SVG 支持哪些元素和属性?

SOUI 支持的 SVG 元素包括: - 基本形状<rect><circle><ellipse><line><polyline><polygon> - 路径<path>(支持 M/L/C/Q/Z/A 等命令) - 填充描边fillstrokestroke-widthfill-opacitystroke-opacity - 渐变<linearGradient><radialGradient> - 变换transform(translate、scale、rotate、matrix) - 文本<text>(SOUI 扩展支持) - 分组<g><defs>

Q2:使用 SVG 后性能会下降吗?

不会明显下降。SOUI 的 SVG 采用纯矢量渲染路径,相比光栅化方案: - 避免了中间位图的内存开销 - 九宫格场景下性能优于位图(无需像素插值) - 缩放时性能稳定,不会因为放大导致性能下降

Q3:SVG 可以和 PNG 混用吗?

可以。皮肤系统会根据资源类型自动选择加载方式,可以在同一个项目中混用 SVG 和 PNG:

<skin>
    <!-- 简单图标使用 SVG -->
    <imglist name="skin_icon_play" src="svg:icon_play" states="4"/>

    <!-- 复杂照片类资源使用 PNG -->
    <imglist name="skin_cover_placeholder" src="png:cover_placeholder"/>
</skin>

Q4:如何调试 SVG 显示问题?

  1. 浏览器预览:用 Chrome/Edge 直接打开 SVG 文件,检查图形是否正确
  2. 检查 viewBox:确保 viewBox 与实际图形范围匹配
  3. 检查单位:避免使用 pxem 等单位,使用纯数字
  4. 简化测试:先用简单图形测试,逐步增加复杂度
  5. 查看日志:开启 SOUI 调试日志,检查资源加载错误

Q5:SOUI 支持动画 SVG 吗?

目前 SOUI 不直接支持 SMIL 动画,但可以通过以下方式实现动画效果:

  1. 多帧动画:使用 imglist 的多状态机制,每帧为一个状态,通过定时器切换状态
  2. 代码动画:通过代码控制绘制位置、缩放、透明度等属性
  3. 属性动画:使用 SOUI 的动画系统控制控件属性

示例:xmusic 项目中的转换动画

<!-- 10 帧转换动画,states=10 -->
<imglist name="skin_icon_converting_anim" src="svg:icon_converting" states="10"/>
// 代码中通过定时器切换帧
void CBatchConvertDlg::OnTimer(UINT_PTR nIDEvent)
{
    static int s_nFrame = 0;
    m_pIconConverting->SetState(s_nFrame % 10);
    s_nFrame++;
}

总结

SOUI 的 SVG 支持方案在保持轻量、高性能的前提下,实现了 SVG 与框架渲染系统的深度整合:

  • 轻量实现:基于 NanoSVG 解析,代码紧凑,集成成本低
  • 深度融合:直接利用 IRenderTarget 矢量渲染能力,避免中间位图开销
  • 完整特性:支持文本、渐变、九宫格等常用 SVG 特性
  • 开发友好:通过 svg: 资源前缀自动识别,与现有皮肤系统无缝协作
  • AI 就绪:文本格式为智能化 UI 设计与生成提供基础

相比将 SVG 光栅化的传统方式,SOUI 的矢量渲染路径在内存、性能、视觉效果和开发效率上均具有显著优势,是现代桌面应用 UI 开发的高效选择。