501 lines
12 KiB
Markdown
501 lines
12 KiB
Markdown
# Phase 2 UI 组件库实现文档
|
||
|
||
**阶段**: Week 3-4
|
||
**交付日期**: 2026-03-07
|
||
**负责人**: UI/UX 设计师
|
||
**状态**: ✅ 已完成
|
||
|
||
---
|
||
|
||
## 📦 交付内容
|
||
|
||
### 任务 1:工具栏组件 ✅
|
||
|
||
**文件**: `lib/presentation/widgets/toolbar_widget.dart`
|
||
|
||
**功能特性**:
|
||
- ✅ 顶部工具栏:撤销/重做/保存/设置
|
||
- ✅ 底部工具栏:元件库/走线模式/选择模式
|
||
- ✅ 支持可折叠/隐藏
|
||
- ✅ 模式切换状态管理
|
||
- ✅ 动画过渡效果
|
||
- ✅ 响应式布局
|
||
|
||
**核心 API**:
|
||
```dart
|
||
ToolbarWidget(
|
||
showTopToolbar: true,
|
||
showBottomToolbar: true,
|
||
collapsible: true,
|
||
onUndo: () => ...,
|
||
onRedo: () => ...,
|
||
onSave: () => ...,
|
||
onSettings: () => ...,
|
||
onComponentLibrary: () => ...,
|
||
onWireMode: () => ...,
|
||
onSelectMode: () => ...,
|
||
)
|
||
```
|
||
|
||
**设计亮点**:
|
||
- 采用 Material Design 卡片式设计
|
||
- 顶部工具栏支持滑动手势收起/展开
|
||
- 底部工具栏模式按钮有高亮状态
|
||
- 工具栏按钮带有 Tooltip 提示
|
||
|
||
---
|
||
|
||
### 任务 2:属性面板组件 ✅
|
||
|
||
**文件**: `lib/presentation/widgets/property_panel_widget.dart`
|
||
|
||
**功能特性**:
|
||
- ✅ 弹出式属性编辑(元件值、封装、网络名)
|
||
- ✅ 实时预览修改效果
|
||
- ✅ 输入验证与错误提示
|
||
- ✅ 位号格式验证(R1, C2, U3)
|
||
- ✅ 元件值格式验证(10k, 100n 等)
|
||
- ✅ 封装格式验证
|
||
- ✅ 旋转控制(0°, 90°, 180°, 270°)
|
||
- ✅ 镜像控制(水平/垂直)
|
||
- ✅ 未保存状态提示
|
||
|
||
**核心 API**:
|
||
```dart
|
||
// 直接使用组件
|
||
PropertyPanelWidget(
|
||
propertyData: PropertyData(
|
||
refDesignator: 'R1',
|
||
value: '10k',
|
||
footprint: '0805',
|
||
componentType: ComponentType.resistor,
|
||
),
|
||
onPropertyChanged: (data) => ...,
|
||
onPreview: (data) => ...,
|
||
)
|
||
|
||
// 或使用辅助函数
|
||
final result = await showPropertyPanel(
|
||
context,
|
||
propertyData: ...,
|
||
onPropertyChanged: (data) => ...,
|
||
);
|
||
```
|
||
|
||
**数据模型**:
|
||
```dart
|
||
class PropertyData {
|
||
String? refDesignator; // 位号
|
||
String? value; // 值
|
||
String? footprint; // 封装
|
||
String? netName; // 网络名
|
||
ComponentType componentType;
|
||
String? symbolName;
|
||
int rotation; // 0, 90, 180, 270
|
||
bool mirrorX;
|
||
bool mirrorY;
|
||
}
|
||
```
|
||
|
||
**验证规则**:
|
||
- 位号:必须为 `字母 + 数字` 格式(如 R1, C2, U3)
|
||
- 电阻值:支持 `10k`, `4.7M`, `100R` 等格式
|
||
- 电容值:支持 `10u`, `100n`, `1p` 等格式
|
||
- 封装:必须包含字母和数字(如 0805, SOT23)
|
||
|
||
**设计亮点**:
|
||
- 底部抽屉式弹出,符合移动端交互习惯
|
||
- 实时输入验证,错误即时提示
|
||
- 旋转按钮可视化展示角度
|
||
- 未保存状态有明显提示
|
||
|
||
---
|
||
|
||
### 任务 3:元件库面板组件 ✅
|
||
|
||
**文件**: `lib/presentation/widgets/component_library_panel.dart`
|
||
|
||
**功能特性**:
|
||
- ✅ 网格/列表双视图切换
|
||
- ✅ 搜索与筛选(按类别、封装、厂商)
|
||
- ✅ 拖拽元件到画布
|
||
- ✅ 类别筛选(FilterChip)
|
||
- ✅ 封装筛选
|
||
- ✅ 搜索防抖(300ms)
|
||
- ✅ 长按查看详情
|
||
- ✅ 可拖拽拖动手柄
|
||
|
||
**核心 API**:
|
||
```dart
|
||
// 直接使用组件
|
||
ComponentLibraryPanel(
|
||
initialViewMode: LibraryViewMode.grid,
|
||
onComponentSelected: (item) => ...,
|
||
onDragStarted: (item) => ...,
|
||
onFilterChanged: (filters) => ...,
|
||
)
|
||
|
||
// 或使用辅助函数(抽屉式)
|
||
await showComponentLibraryDrawer(
|
||
context,
|
||
initialViewMode: LibraryViewMode.grid,
|
||
onComponentSelected: (item) => ...,
|
||
);
|
||
```
|
||
|
||
**数据模型**:
|
||
```dart
|
||
class ComponentLibraryItem {
|
||
final String name;
|
||
final String category;
|
||
final String footprint;
|
||
final String? description;
|
||
final String? manufacturer;
|
||
final String? symbolData;
|
||
}
|
||
|
||
enum LibraryViewMode {
|
||
grid, // 网格视图
|
||
list, // 列表视图
|
||
}
|
||
```
|
||
|
||
**筛选功能**:
|
||
- 类别:电源、被动元件、半导体、连接器、光电器件、集成电路
|
||
- 封装:0402, 0603, 0805, 1206, SOT23, SOT223, SOIC8, DIP8, QFN16
|
||
- 搜索:支持名称和描述模糊匹配
|
||
|
||
**拖拽支持**:
|
||
- 使用 Flutter Draggable 组件
|
||
- 拖拽时显示半透明原位置
|
||
- 拖拽反馈组件带有高亮边框
|
||
- 支持长按查看详情后再拖拽
|
||
|
||
**设计亮点**:
|
||
- 网格视图:2 列布局,卡片式设计
|
||
- 列表视图:ListTile 布局,信息更详细
|
||
- 搜索栏带清除按钮
|
||
- 筛选面板可展开/收起
|
||
- 空状态友好提示
|
||
|
||
---
|
||
|
||
## 🎨 设计规范
|
||
|
||
### 遵循 Phase 1 触摸交互规范 v1.0
|
||
|
||
1. **最小触控区域**: 所有按钮 ≥ 44x44pt(iOS 人机指南)
|
||
2. **手势支持**:
|
||
- 单击:选择/触发
|
||
- 长按:上下文菜单/详情
|
||
- 拖拽:元件放置
|
||
- 双指缩放:画布导航(编辑器层面)
|
||
3. **视觉反馈**:
|
||
- 按钮按下有涟漪效果
|
||
- 选中状态有高亮
|
||
- 拖拽时有半透明提示
|
||
4. **动画过渡**: 200ms 标准动画时长
|
||
|
||
### Material Design 3 风格
|
||
|
||
- 圆角:8px(小组件)、12px(卡片)、16px(面板)
|
||
- 阴影:轻度阴影(模糊 8px,偏移 0,2)
|
||
- 配色:使用 Theme.of(context).primaryColor
|
||
- 字体:系统默认字体,字号 10-20sp
|
||
|
||
---
|
||
|
||
## 🔌 集成指南
|
||
|
||
### 1. 在原理图编辑器中集成
|
||
|
||
```dart
|
||
import 'package:mobile_eda/presentation/widgets/widgets.dart';
|
||
|
||
class SchematicEditorScreen extends ConsumerStatefulWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
body: Stack(
|
||
children: [
|
||
// 画布
|
||
SchematicCanvas(),
|
||
|
||
// 工具栏
|
||
ToolbarWidget(
|
||
onUndo: _undo,
|
||
onRedo: _redo,
|
||
onSave: _save,
|
||
onSettings: _showSettings,
|
||
onComponentLibrary: _showLibrary,
|
||
onWireMode: _setWireMode,
|
||
onSelectMode: _setSelectMode,
|
||
),
|
||
],
|
||
),
|
||
// 或作为底部抽屉显示元件库
|
||
bottomSheet: ComponentLibraryPanel(
|
||
onComponentSelected: _addComponent,
|
||
),
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 属性编辑集成
|
||
|
||
```dart
|
||
// 双击元件时显示属性面板
|
||
void _onComponentDoubleTap(SchematicComponent component) async {
|
||
final propertyData = PropertyData(
|
||
refDesignator: component.ref,
|
||
value: component.value,
|
||
footprint: component.footprint,
|
||
componentType: _mapToComponentType(component.type),
|
||
rotation: component.rotation,
|
||
mirrorX: component.mirrorX,
|
||
mirrorY: component.mirrorY,
|
||
);
|
||
|
||
final result = await showPropertyPanel(
|
||
context,
|
||
propertyData: propertyData,
|
||
onPreview: (data) {
|
||
// 实时预览:临时更新画布显示
|
||
_previewComponentChanges(data);
|
||
},
|
||
onPropertyChanged: (data) {
|
||
// 应用更改
|
||
_updateComponent(component.id, data);
|
||
},
|
||
);
|
||
|
||
if (result != null) {
|
||
// 保存成功
|
||
_commitChanges();
|
||
} else {
|
||
// 取消,恢复原状
|
||
_revertPreview();
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 元件拖拽集成
|
||
|
||
```dart
|
||
// 在画布上接收拖拽
|
||
class SchematicCanvas extends StatefulWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return DragTarget<ComponentLibraryItem>(
|
||
onWillAccept: (data) => true,
|
||
onAccept: (component) {
|
||
// 在拖拽位置放置元件
|
||
_placeComponent(component, _lastDragPosition);
|
||
},
|
||
builder: (context, candidateData, rejectedData) {
|
||
return CustomPaint(painter: SchematicPainter());
|
||
},
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. Riverpod 状态管理集成
|
||
|
||
```dart
|
||
// 创建状态提供者
|
||
final toolbarModeProvider = StateProvider<ToolbarMode>((ref) {
|
||
return ToolbarMode.select;
|
||
});
|
||
|
||
final propertyPanelProvider = StateProvider<PropertyData?>((ref) {
|
||
return null;
|
||
});
|
||
|
||
final componentLibraryFilterProvider = StateProvider<FilterOptions>((ref) {
|
||
return FilterOptions();
|
||
});
|
||
|
||
// 在组件中使用
|
||
class _SchematicEditorScreenState extends ConsumerState {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final mode = ref.watch(toolbarModeProvider);
|
||
|
||
return ToolbarWidget(
|
||
onSelectMode: () => ref.read(toolbarModeProvider.notifier).state = ToolbarMode.select,
|
||
onWireMode: () => ref.read(toolbarModeProvider.notifier).state = ToolbarMode.wire,
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 文件结构
|
||
|
||
```
|
||
mobile-eda/lib/presentation/widgets/
|
||
├── widgets.dart # 导出文件(barrel)
|
||
├── toolbar_widget.dart # 工具栏组件
|
||
├── property_panel_widget.dart # 属性面板组件
|
||
└── component_library_panel.dart # 元件库面板组件
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 测试建议
|
||
|
||
### 单元测试
|
||
|
||
```dart
|
||
test('PropertyData copy creates independent copy', () {
|
||
final original = PropertyData(
|
||
refDesignator: 'R1',
|
||
value: '10k',
|
||
componentType: ComponentType.resistor,
|
||
);
|
||
|
||
final copy = original.copy();
|
||
copy.refDesignator = 'R2';
|
||
|
||
expect(original.refDesignator, equals('R1'));
|
||
expect(copy.refDesignator, equals('R2'));
|
||
});
|
||
|
||
test('ToolbarWidget callbacks are invoked', () {
|
||
var undoCalled = false;
|
||
|
||
final widget = ToolbarWidget(
|
||
onUndo: () => undoCalled = true,
|
||
);
|
||
|
||
// 使用 tester.tap() 模拟点击撤销按钮
|
||
// expect(undoCalled, isTrue);
|
||
});
|
||
```
|
||
|
||
### 组件测试
|
||
|
||
```dart
|
||
testWidgets('PropertyPanelWidget validates ref designator', (tester) async {
|
||
await tester.pumpWidget(
|
||
MaterialApp(
|
||
home: PropertyPanelWidget(
|
||
propertyData: PropertyData(
|
||
componentType: ComponentType.resistor,
|
||
),
|
||
),
|
||
),
|
||
);
|
||
|
||
// 输入无效位号
|
||
await tester.enterText(find.byType(TextFormField).first, 'invalid');
|
||
await tester.pump();
|
||
|
||
// 验证错误提示
|
||
expect(find.text('位号格式错误 (如 R1, C2, U3)'), findsOneWidget);
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 后续优化建议
|
||
|
||
### 性能优化
|
||
1. **元件库懒加载**: 当元件数量 > 100 时,使用分页或虚拟列表
|
||
2. **图片缓存**: 元件符号图片使用 cached_network_image
|
||
3. **防抖优化**: 搜索已实现 300ms 防抖
|
||
|
||
### 功能增强
|
||
1. **最近使用**: 添加"最近使用元件"快速访问
|
||
2. **收藏功能**: 允许用户收藏常用元件
|
||
3. **自定义元件**: 支持用户创建和导入自定义元件
|
||
4. **批量编辑**: 支持多选元件批量修改属性
|
||
|
||
### 用户体验
|
||
1. **快捷键支持**: 桌面端可添加键盘快捷键(Ctrl+Z 撤销等)
|
||
2. **语音输入**: 支持语音输入元件值("十千欧")
|
||
3. **AR 预览**: 使用 AR 查看元件实物图
|
||
|
||
---
|
||
|
||
## 📞 与 EDA 引擎专家协作
|
||
|
||
### 需要对接的 API
|
||
|
||
1. **元件放置**:
|
||
```dart
|
||
// 需要 EDA 引擎提供
|
||
void placeComponent(ComponentLibraryItem item, Offset position);
|
||
```
|
||
|
||
2. **属性更新**:
|
||
```dart
|
||
// 需要 EDA 引擎提供
|
||
void updateComponentProperties(String componentId, PropertyData properties);
|
||
```
|
||
|
||
3. **模式切换**:
|
||
```dart
|
||
// 需要 EDA 引擎提供
|
||
void setEditorMode(EditorMode mode);
|
||
```
|
||
|
||
4. **撤销/重做**:
|
||
```dart
|
||
// 需要 EDA 引擎提供
|
||
void undo();
|
||
void redo();
|
||
bool get canUndo;
|
||
bool get canRedo;
|
||
```
|
||
|
||
### 数据格式约定
|
||
|
||
```dart
|
||
// 元件唯一标识
|
||
typedef ComponentId = String;
|
||
|
||
// 坐标系统
|
||
// - 画布坐标:逻辑像素,原点在左上角
|
||
// - 网格吸附:默认 10.0 网格大小
|
||
|
||
// 旋转角度
|
||
// - 0: 默认方向
|
||
// - 90: 顺时针 90 度
|
||
// - 180: 顺时针 180 度
|
||
// - 270: 顺时针 270 度
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 验收标准
|
||
|
||
- [x] 工具栏组件可正常显示/隐藏
|
||
- [x] 工具栏按钮点击有响应
|
||
- [x] 属性面板可弹出/关闭
|
||
- [x] 属性输入有验证提示
|
||
- [x] 元件库支持网格/列表切换
|
||
- [x] 元件库支持搜索筛选
|
||
- [x] 元件可拖拽(Draggable)
|
||
- [x] 代码符合 Flutter 规范(flutter analyze 通过)
|
||
- [x] 组件文档完整
|
||
|
||
---
|
||
|
||
## 📝 更新日志
|
||
|
||
**2026-03-07** - 初始版本
|
||
- ✅ 完成工具栏组件
|
||
- ✅ 完成属性面板组件
|
||
- ✅ 完成元件库面板组件
|
||
- ✅ 编写集成文档
|
||
|
||
---
|
||
|
||
**交付完成** 🎉
|
||
|
||
所有组件已实现并经过基本测试,可集成到原理图编辑器中使用。
|