Skip to content

在 SOUI 中使用 SVG

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

概述

在高分屏时代,传统位图资源(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 开发的高效选择。