# Flutter SVG 未居中问题

> **问题标签**: `svg`, `viewbox`, `center`, `alignment`, `icon`, `chevron`, `设计稿还原`, `旧资源复用`  
> **框架**: Flutter  
> **严重程度**: 低（布局问题）

---

## 🔍 问题识别

### 用户描述关键词
- "SVG 图标没有居中"
- "图标位置偏了"
- "需要用 Center 包裹"
- "viewBox 不对"

### 问题特征
- [ ] SVG 显示位置与预期不符
- [ ] 需要额外的 Center/Align 组件包裹
- [ ] SVG viewBox 尺寸与使用尺寸不匹配
- [ ] 16×16 的槽位里实际只应渲染 6×8 或 12×12 的图形
- [ ] 复用了其它页面的同名箭头资源，导致 viewBox 与当前页面不一致

---

## 🎯 核心原理

**根本原因**：Sketch 导出 SVG 时，viewBox 可能是图形的最小边界框，而非设计稿中的容器尺寸。

设计稿还原里另一个高频根因是“旧资源复用”：其它页面的同名箭头虽然名字相近，但它的 viewBox、path 偏移、透明度可能都不是当前页面这一个。看起来像同一种 chevron，实际上不能直接共用。

```xml
<!-- ❌ 问题：viewBox 是最小边界框 -->
<!-- 箭头图标实际尺寸是 6x3，但需要放在 12x12 的容器中 -->
<svg viewBox="0 0 6 3">
  <path d="..."/>
</svg>
```

```dart
// 放在 12x12 容器中，图标会被拉伸或需要额外居中处理
SvgPicture.asset('arrow.svg', width: 12, height: 12);
```

---

## ✅ 正确解决方案

### 方案1：导出时保留完整 viewBox（推荐）

在 Sketch 中导出 SVG 时，选择图标所在的外层容器（Group），而非内部的形状：

```javascript
// Sketch 脚本：导出完整容器的 SVG
const sketch = require('sketch');
const layer = sketch.find('[name="Icon Container"]')[0]; // 选择外层 Group
const svg = sketch.export(layer, { formats: 'svg', output: false });
```

```xml
<!-- ✅ 正确：viewBox 包含完整容器空间 -->
<svg viewBox="0 0 12 12">
  <!-- 箭头在容器中的正确位置 -->
  <path transform="translate(3, 4.5)" d="..."/>
</svg>
```

### 方案2：Flutter 中手动设置对齐

```dart
// 如果 SVG 无法重新导出，在 Flutter 中处理
SizedBox(
  width: 12,
  height: 12,
  child: Center(
    child: SvgPicture.asset(
      'arrow.svg',
      width: 6,  // 使用 SVG 实际尺寸
      height: 3,
    ),
  ),
)
```

### 方案3：区分槽位尺寸和图形尺寸

```dart
// ✅ 16×16 槽位中居中渲染 6×8 图形
SizedBox(
  width: 16,
  height: 16,
  child: Center(
    child: SvgPicture.asset(
      '<asset-dir>/recipient_chevron_right.svg',
      width: 6,
      height: 8,
    ),
  ),
)

// ❌ 错误 - 直接把 6×8 箭头按 16×16 渲染，视觉会偏大
SvgPicture.asset('<asset-dir>/recipient_chevron_right.svg', width: 16, height: 16)
```

---

## 📝 Sketch 图标导出检查清单

1. **确认选择正确的图层**
   - 选择外层 Group/Frame，而非内部 Shape
   - 外层应该是设计稿中图标的"点击区域"尺寸

2. **验证导出的 viewBox**
   ```bash
   # 检查 SVG 文件的 viewBox
  head -3 <asset-dir>/arrow.svg
   # 应该看到 viewBox="0 0 12 12" 而非 viewBox="0 0 6 3"
   ```

3. **检查 Flutter 中的使用**
   ```dart
   // 宽高应该与 viewBox 匹配
   SvgPicture.asset('arrow.svg', width: 12, height: 12);
   ```

4. **检查是否误复用旧资产**
  - 当前页面箭头是否从当前画板重新导出
  - 是否拿了其它页面的全局 `ic_chevron_right.svg` 直接顶替
  - 当前页面的 path 实际尺寸是否和设计稿一致（如 6×8）

---

## ❌ 常见错误排查路线（避免重复）

| 尝试方向 | 为什么无效 | 浪费时间 |
|----------|-----------|---------|
| 用 Center 包裹 | 治标不治本，每个图标都要处理 | 1 轮对话/图标 |
| 调整 alignment 属性 | SvgPicture 的 alignment 可能不生效 | 1-2 轮对话 |
| 修改 SVG 的 transform | 需要计算精确偏移量 | 2-3 轮对话 |

**最佳做法**：从源头修复，重新导出正确 viewBox 的 SVG

---

## 📁 适用场景

- ✅ 小尺寸图标（箭头、点击指示器等）
- ✅ 需要放在固定容器中的图标
- ✅ TabBar、按钮中的图标
