first commit
This commit is contained in:
349
basic_uis/README.md
Normal file
349
basic_uis/README.md
Normal file
@@ -0,0 +1,349 @@
|
||||
# Basic UIs 基础UI组件模块群
|
||||
|
||||
## 模块群概述
|
||||
|
||||
Basic UIs 模块群是 OneApp 的用户界面基础设施,提供了完整的UI组件生态系统。该模块群包含了基础UI组件、业务UI组件和通用UI组件,为整个应用提供统一的设计语言和用户体验。
|
||||
|
||||
## 子模块列表
|
||||
|
||||
### 核心UI组件
|
||||
1. **[ui_basic](./ui_basic.md)** - 基础UI组件库
|
||||
- 按钮、输入框、卡片等基础组件
|
||||
- 布局容器和交互组件
|
||||
- 主题系统和响应式设计
|
||||
|
||||
2. **[ui_business](./ui_business.md)** - 业务UI组件库
|
||||
- 车辆状态展示组件
|
||||
- 消息中心组件
|
||||
- 地理位置组件
|
||||
- 用户同意组件
|
||||
|
||||
3. **[basic_uis](./basic_uis.md)** - 通用UI组件集合
|
||||
- 组件库整合和统一导出
|
||||
- 跨模块UI组件管理
|
||||
- 全局UI配置和工具
|
||||
|
||||
4. **[general_ui_component](./general_ui_component.md)** - 通用UI组件
|
||||
- 可复用的通用组件
|
||||
- 跨业务场景组件
|
||||
- 第三方组件封装
|
||||
|
||||
## 模块架构
|
||||
|
||||
### 分层设计
|
||||
```
|
||||
应用层 UI 组件
|
||||
↓
|
||||
业务层 UI 组件 (ui_business)
|
||||
↓
|
||||
基础层 UI 组件 (ui_basic)
|
||||
↓
|
||||
Flutter Framework
|
||||
```
|
||||
|
||||
### 组件分类
|
||||
|
||||
#### 1. 基础组件层 (ui_basic)
|
||||
- **原子组件**: Button, TextField, Icon, Text
|
||||
- **分子组件**: Card, ListTile, AppBar, Dialog
|
||||
- **布局组件**: Container, Row, Column, Stack
|
||||
- **交互组件**: GestureDetector, InkWell, RefreshIndicator
|
||||
|
||||
#### 2. 业务组件层 (ui_business)
|
||||
- **车辆组件**: VehicleStatusCard, VehicleControlPanel
|
||||
- **消息组件**: MessageListView, MessageTile
|
||||
- **位置组件**: LocationPicker, MapView
|
||||
- **表单组件**: BusinessForm, ConsentDialog
|
||||
|
||||
#### 3. 通用组件层 (basic_uis & general_ui_component)
|
||||
- **复合组件**: SearchBar, NavigationDrawer
|
||||
- **特效组件**: AnimatedWidget, TransitionWidget
|
||||
- **工具组件**: LoadingOverlay, ErrorBoundary
|
||||
|
||||
## 设计原则
|
||||
|
||||
### 1. 一致性原则
|
||||
- **视觉一致性**: 统一的颜色、字体、间距规范
|
||||
- **交互一致性**: 统一的交互模式和反馈机制
|
||||
- **行为一致性**: 相同功能组件的行为保持一致
|
||||
|
||||
### 2. 可访问性原则
|
||||
- **语义标签**: 为屏幕阅读器提供清晰的语义
|
||||
- **键盘导航**: 支持键盘和辅助设备导航
|
||||
- **对比度**: 满足无障碍对比度要求
|
||||
- **字体缩放**: 支持系统字体缩放设置
|
||||
|
||||
### 3. 响应式原则
|
||||
- **屏幕适配**: 适应不同屏幕尺寸和密度
|
||||
- **方向适配**: 支持横竖屏切换
|
||||
- **设备适配**: 针对手机、平板的优化
|
||||
- **性能适配**: 根据设备性能调整渲染策略
|
||||
|
||||
### 4. 可扩展性原则
|
||||
- **插件化**: 支持组件插件化扩展
|
||||
- **主题化**: 支持多主题和自定义主题
|
||||
- **国际化**: 支持多语言和本地化
|
||||
- **配置化**: 通过配置控制组件行为
|
||||
|
||||
## 主题系统
|
||||
|
||||
### 主题架构
|
||||
```dart
|
||||
class OneAppTheme {
|
||||
// 颜色系统
|
||||
static ColorScheme get colorScheme => ColorScheme.fromSeed(
|
||||
seedColor: const Color(0xFF1976D2),
|
||||
);
|
||||
|
||||
// 字体系统
|
||||
static TextTheme get textTheme => const TextTheme(
|
||||
displayLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||
titleLarge: TextStyle(fontSize: 20, fontWeight: FontWeight.w600),
|
||||
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.normal),
|
||||
);
|
||||
|
||||
// 组件主题
|
||||
static ThemeData get lightTheme => ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: colorScheme,
|
||||
textTheme: textTheme,
|
||||
appBarTheme: const AppBarTheme(/* ... */),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(/* ... */),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 设计令牌 (Design Tokens)
|
||||
```dart
|
||||
class DesignTokens {
|
||||
// 间距系统
|
||||
static const double spacingXs = 4.0;
|
||||
static const double spacingSm = 8.0;
|
||||
static const double spacingMd = 16.0;
|
||||
static const double spacingLg = 24.0;
|
||||
static const double spacingXl = 32.0;
|
||||
|
||||
// 圆角系统
|
||||
static const double radiusXs = 4.0;
|
||||
static const double radiusSm = 8.0;
|
||||
static const double radiusMd = 12.0;
|
||||
static const double radiusLg = 16.0;
|
||||
|
||||
// 阴影系统
|
||||
static const List<BoxShadow> shadowSm = [
|
||||
BoxShadow(
|
||||
color: Color(0x0D000000),
|
||||
blurRadius: 2,
|
||||
offset: Offset(0, 1),
|
||||
),
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
## 组件开发规范
|
||||
|
||||
### 1. 组件结构
|
||||
```dart
|
||||
class ExampleComponent extends StatelessWidget {
|
||||
// 1. 必需参数
|
||||
final String title;
|
||||
|
||||
// 2. 可选参数
|
||||
final String? subtitle;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
// 3. 样式参数
|
||||
final TextStyle? titleStyle;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
// 4. 构造函数
|
||||
const ExampleComponent({
|
||||
Key? key,
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.onTap,
|
||||
this.titleStyle,
|
||||
this.padding,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(/* 实现 */);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 命名规范
|
||||
- **组件名称**: 使用PascalCase,如 `VehicleStatusCard`
|
||||
- **参数名称**: 使用camelCase,如 `onPressed`
|
||||
- **常量名称**: 使用camelCase,如 `defaultPadding`
|
||||
- **枚举名称**: 使用PascalCase,如 `ButtonType`
|
||||
|
||||
### 3. 文档规范
|
||||
```dart
|
||||
/// 车辆状态卡片组件
|
||||
///
|
||||
/// 用于展示车辆的基本状态信息,包括电量、里程、锁定状态等。
|
||||
/// 支持点击交互和自定义样式。
|
||||
///
|
||||
/// 示例用法:
|
||||
/// ```dart
|
||||
/// VehicleStatusCard(
|
||||
/// status: vehicleStatus,
|
||||
/// onTap: () => Navigator.push(...),
|
||||
/// )
|
||||
/// ```
|
||||
class VehicleStatusCard extends StatelessWidget {
|
||||
/// 车辆状态数据
|
||||
final VehicleStatus status;
|
||||
|
||||
/// 点击回调函数
|
||||
final VoidCallback? onTap;
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化策略
|
||||
|
||||
### 1. 渲染优化
|
||||
- **Widget缓存**: 缓存不变的Widget实例
|
||||
- **RepaintBoundary**: 隔离重绘区域
|
||||
- **Const构造**: 使用const构造函数
|
||||
- **Build优化**: 避免在build方法中创建对象
|
||||
|
||||
### 2. 内存优化
|
||||
- **资源释放**: 及时释放Controller和Stream
|
||||
- **图片缓存**: 合理使用图片缓存策略
|
||||
- **对象池**: 复用频繁创建的对象
|
||||
- **弱引用**: 避免内存泄漏
|
||||
|
||||
### 3. 加载优化
|
||||
- **懒加载**: 按需加载组件和资源
|
||||
- **预加载**: 预测性加载关键资源
|
||||
- **分包加载**: 大型组件分包异步加载
|
||||
- **缓存策略**: 智能缓存机制
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 1. 单元测试
|
||||
```dart
|
||||
testWidgets('VehicleStatusCard displays correct information', (tester) async {
|
||||
const status = VehicleStatus(
|
||||
vehicleName: 'Test Vehicle',
|
||||
batteryLevel: 80,
|
||||
isLocked: true,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: VehicleStatusCard(status: status),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('Test Vehicle'), findsOneWidget);
|
||||
expect(find.text('80%'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.lock), findsOneWidget);
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Widget测试
|
||||
- **渲染测试**: 验证组件正确渲染
|
||||
- **交互测试**: 测试用户交互响应
|
||||
- **状态测试**: 测试状态变化
|
||||
- **样式测试**: 验证样式正确应用
|
||||
|
||||
### 3. 集成测试
|
||||
- **页面流程测试**: 测试完整用户流程
|
||||
- **性能测试**: 测试组件性能表现
|
||||
- **兼容性测试**: 测试不同设备兼容性
|
||||
- **可访问性测试**: 测试无障碍功能
|
||||
|
||||
## 构建和发布
|
||||
|
||||
### 1. 版本管理
|
||||
- **语义化版本**: 遵循 semver 规范
|
||||
- **变更日志**: 详细的变更记录
|
||||
- **向后兼容**: 保证API向后兼容
|
||||
- **废弃通知**: 提前通知API废弃
|
||||
|
||||
### 2. 发布流程
|
||||
```bash
|
||||
# 1. 运行测试
|
||||
flutter test
|
||||
|
||||
# 2. 更新版本号
|
||||
# 编辑 pubspec.yaml
|
||||
|
||||
# 3. 更新变更日志
|
||||
# 编辑 CHANGELOG.md
|
||||
|
||||
# 4. 发布包
|
||||
flutter pub publish
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 1. 快速开始
|
||||
```dart
|
||||
import 'package:ui_basic/ui_basic.dart';
|
||||
import 'package:ui_business/ui_business.dart';
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
theme: OneAppTheme.lightTheme,
|
||||
home: MyHomePage(),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 组件使用
|
||||
```dart
|
||||
// 基础组件使用
|
||||
BasicButton(
|
||||
text: '确定',
|
||||
type: ButtonType.primary,
|
||||
onPressed: () {},
|
||||
)
|
||||
|
||||
// 业务组件使用
|
||||
VehicleStatusCard(
|
||||
status: vehicleStatus,
|
||||
onTap: () {},
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 主题定制
|
||||
```dart
|
||||
MaterialApp(
|
||||
theme: OneAppTheme.lightTheme.copyWith(
|
||||
primarySwatch: Colors.green,
|
||||
// 其他自定义配置
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 组件设计
|
||||
- **单一职责**: 每个组件功能单一明确
|
||||
- **可组合性**: 支持组件组合使用
|
||||
- **可配置性**: 提供丰富的配置选项
|
||||
- **可预测性**: 相同输入产生相同输出
|
||||
|
||||
### 2. API设计
|
||||
- **直观性**: API命名直观易理解
|
||||
- **一致性**: 相似功能API保持一致
|
||||
- **扩展性**: 预留扩展空间
|
||||
- **文档化**: 提供完整文档和示例
|
||||
|
||||
### 3. 性能考虑
|
||||
- **懒加载**: 按需加载减少初始化开销
|
||||
- **缓存策略**: 合理使用缓存提升性能
|
||||
- **异步处理**: 避免阻塞UI线程
|
||||
- **资源管理**: 及时释放不需要的资源
|
||||
|
||||
## 总结
|
||||
|
||||
Basic UIs 模块群为 OneApp 提供了完整的UI基础设施,通过分层设计、统一规范和完善的工具链,实现了高效的UI开发和一致的用户体验。模块群具有良好的可扩展性和可维护性,能够支撑大型应用的UI需求,并为未来的功能扩展提供了坚实的基础。
|
||||
737
basic_uis/basic_uis.md
Normal file
737
basic_uis/basic_uis.md
Normal file
@@ -0,0 +1,737 @@
|
||||
# Basic UIs 通用UI组件集合模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`basic_uis` 是 OneApp 基础UI模块群中的通用UI组件集合模块,负责整合和统一管理所有的UI组件库。该模块提供了一站式的UI组件解决方案,包含了动画效果、权限管理、分享功能、地图集成等丰富的UI功能组件。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: basic_uis
|
||||
- **版本**: 0.0.7
|
||||
- **描述**: 通用UI组件集合包
|
||||
- **Flutter 版本**: >=1.17.0
|
||||
- **Dart 版本**: >=3.0.0 <4.0.0
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
1. **UI组件整合**
|
||||
- 统一的UI组件导出
|
||||
- 组件库版本管理
|
||||
- 跨模块组件协调
|
||||
- 全局UI配置管理
|
||||
|
||||
2. **高级UI组件**
|
||||
- 下拉刷新组件集成
|
||||
- Lottie动画支持
|
||||
- WebView组件封装
|
||||
- 地图视图集成
|
||||
|
||||
3. **用户交互组件**
|
||||
- 权限管理UI组件
|
||||
- 分享功能UI集成
|
||||
- 图片保存组件
|
||||
- 设置页面组件
|
||||
|
||||
4. **系统集成组件**
|
||||
- 位置服务UI
|
||||
- 应用设置界面
|
||||
- 用户同意组件
|
||||
- Toast消息提示
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── basic_uis.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── components/ # 通用组件
|
||||
│ ├── animations/ # 动画组件
|
||||
│ ├── permissions/ # 权限组件
|
||||
│ ├── sharing/ # 分享组件
|
||||
│ ├── webview/ # WebView组件
|
||||
│ ├── location/ # 位置组件
|
||||
│ ├── settings/ # 设置组件
|
||||
│ └── utils/ # 工具类
|
||||
├── widgets/ # Widget导出
|
||||
└── themes/ # 主题配置
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
#### UI框架依赖
|
||||
- `easy_refresh: ^3.0.5` - 下拉刷新组件
|
||||
- `lottie: ^3.1.0` - Lottie动画
|
||||
- `fluttertoast: ^8.2.2` - Toast提示
|
||||
- `helpers: ^1.2.3+1` - 辅助工具
|
||||
|
||||
#### 功能组件依赖
|
||||
- `basic_webview: ^0.2.4+4` - WebView组件
|
||||
- `permission_handler: ^10.4.5` - 权限管理
|
||||
- `image_gallery_saver: any` - 图片保存
|
||||
- `share_plus: 7.2.1` - 分享功能
|
||||
- `flutter_inappwebview: ^6.0.0` - 应用内WebView
|
||||
|
||||
#### 业务组件依赖
|
||||
- `app_consent: ^0.2.19` - 用户同意组件
|
||||
- `ui_mapview: ^0.2.18` - 地图视图组件
|
||||
- `app_settings: ^4.3.1` - 应用设置
|
||||
- `location: ^6.0.1` - 位置服务
|
||||
|
||||
#### 内部依赖
|
||||
- `basic_utils` - 基础工具(本地路径)
|
||||
|
||||
## 核心组件分析
|
||||
|
||||
### 1. 模块入口 (`basic_uis.dart`)
|
||||
|
||||
**功能职责**:
|
||||
- 统一导出所有UI组件
|
||||
- 初始化全局UI配置
|
||||
- 管理组件生命周期
|
||||
|
||||
```dart
|
||||
library basic_uis;
|
||||
|
||||
// 基础组件导出
|
||||
export 'src/components/enhanced_refresh_indicator.dart';
|
||||
export 'src/components/lottie_animation_widget.dart';
|
||||
export 'src/components/permission_request_dialog.dart';
|
||||
export 'src/components/share_action_sheet.dart';
|
||||
|
||||
// WebView组件导出
|
||||
export 'src/webview/enhanced_webview.dart';
|
||||
export 'src/webview/webview_controller.dart';
|
||||
|
||||
// 位置组件导出
|
||||
export 'src/location/location_picker_widget.dart';
|
||||
export 'src/location/map_integration_widget.dart';
|
||||
|
||||
// 设置组件导出
|
||||
export 'src/settings/app_settings_page.dart';
|
||||
export 'src/settings/permission_settings_widget.dart';
|
||||
|
||||
// 工具类导出
|
||||
export 'src/utils/ui_helpers.dart';
|
||||
export 'src/utils/toast_utils.dart';
|
||||
|
||||
class BasicUIs {
|
||||
static bool _isInitialized = false;
|
||||
|
||||
/// 初始化Basic UIs模块
|
||||
static Future<void> initialize() async {
|
||||
if (_isInitialized) return;
|
||||
|
||||
// 初始化Toast配置
|
||||
await _initializeToast();
|
||||
|
||||
// 初始化权限处理器
|
||||
await _initializePermissions();
|
||||
|
||||
// 初始化分享服务
|
||||
await _initializeShare();
|
||||
|
||||
// 初始化WebView配置
|
||||
await _initializeWebView();
|
||||
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 增强下拉刷新组件 (`src/components/enhanced_refresh_indicator.dart`)
|
||||
|
||||
```dart
|
||||
class EnhancedRefreshIndicator extends StatefulWidget {
|
||||
final Widget child;
|
||||
final Future<void> Function() onRefresh;
|
||||
final Future<void> Function()? onLoadMore;
|
||||
final RefreshIndicatorConfig? config;
|
||||
final bool enablePullUp;
|
||||
final bool enablePullDown;
|
||||
|
||||
const EnhancedRefreshIndicator({
|
||||
Key? key,
|
||||
required this.child,
|
||||
required this.onRefresh,
|
||||
this.onLoadMore,
|
||||
this.config,
|
||||
this.enablePullUp = true,
|
||||
this.enablePullDown = true,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<EnhancedRefreshIndicator> createState() => _EnhancedRefreshIndicatorState();
|
||||
}
|
||||
|
||||
class _EnhancedRefreshIndicatorState extends State<EnhancedRefreshIndicator> {
|
||||
late EasyRefreshController _controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return EasyRefresh(
|
||||
controller: _controller,
|
||||
onRefresh: widget.enablePullDown ? _onRefresh : null,
|
||||
onLoad: widget.enablePullUp && widget.onLoadMore != null ? _onLoad : null,
|
||||
header: _buildRefreshHeader(),
|
||||
footer: _buildLoadFooter(),
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRefreshHeader() {
|
||||
return ClassicHeader(
|
||||
dragText: '下拉刷新',
|
||||
armedText: '释放刷新',
|
||||
readyText: '正在刷新...',
|
||||
processingText: '正在刷新...',
|
||||
processedText: '刷新完成',
|
||||
noMoreText: '没有更多数据',
|
||||
failedText: '刷新失败',
|
||||
messageText: '最后更新于 %T',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadFooter() {
|
||||
return ClassicFooter(
|
||||
dragText: '上拉加载',
|
||||
armedText: '释放加载',
|
||||
readyText: '正在加载...',
|
||||
processingText: '正在加载...',
|
||||
processedText: '加载完成',
|
||||
noMoreText: '没有更多数据',
|
||||
failedText: '加载失败',
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Lottie动画组件 (`src/animations/lottie_animation_widget.dart`)
|
||||
|
||||
```dart
|
||||
class LottieAnimationWidget extends StatefulWidget {
|
||||
final String assetPath;
|
||||
final double? width;
|
||||
final double? height;
|
||||
final bool repeat;
|
||||
final bool autoPlay;
|
||||
final AnimationController? controller;
|
||||
final VoidCallback? onComplete;
|
||||
|
||||
const LottieAnimationWidget({
|
||||
Key? key,
|
||||
required this.assetPath,
|
||||
this.width,
|
||||
this.height,
|
||||
this.repeat = true,
|
||||
this.autoPlay = true,
|
||||
this.controller,
|
||||
this.onComplete,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LottieAnimationWidget> createState() => _LottieAnimationWidgetState();
|
||||
}
|
||||
|
||||
class _LottieAnimationWidgetState extends State<LottieAnimationWidget>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_animationController = widget.controller ??
|
||||
AnimationController(vsync: this);
|
||||
|
||||
if (widget.autoPlay) {
|
||||
_animationController.forward();
|
||||
}
|
||||
|
||||
_animationController.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
widget.onComplete?.call();
|
||||
if (widget.repeat) {
|
||||
_animationController.repeat();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Lottie.asset(
|
||||
widget.assetPath,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
controller: _animationController,
|
||||
onLoaded: (composition) {
|
||||
_animationController.duration = composition.duration;
|
||||
if (widget.autoPlay) {
|
||||
_animationController.forward();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
if (widget.controller == null) {
|
||||
_animationController.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 权限请求对话框 (`src/permissions/permission_request_dialog.dart`)
|
||||
|
||||
```dart
|
||||
class PermissionRequestDialog extends StatelessWidget {
|
||||
final Permission permission;
|
||||
final String title;
|
||||
final String description;
|
||||
final String? rationale;
|
||||
final VoidCallback? onGranted;
|
||||
final VoidCallback? onDenied;
|
||||
|
||||
const PermissionRequestDialog({
|
||||
Key? key,
|
||||
required this.permission,
|
||||
required this.title,
|
||||
required this.description,
|
||||
this.rationale,
|
||||
this.onGranted,
|
||||
this.onDenied,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Row(
|
||||
children: [
|
||||
Icon(_getPermissionIcon(), color: Theme.of(context).primaryColor),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(child: Text(title)),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(description),
|
||||
if (rationale != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.info_outline,
|
||||
color: Colors.blue, size: 20),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
rationale!,
|
||||
style: TextStyle(
|
||||
color: Colors.blue[700],
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
onDenied?.call();
|
||||
},
|
||||
child: const Text('拒绝'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
final status = await permission.request();
|
||||
if (status.isGranted) {
|
||||
onGranted?.call();
|
||||
} else {
|
||||
onDenied?.call();
|
||||
if (status.isPermanentlyDenied) {
|
||||
_showSettingsDialog(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: const Text('允许'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getPermissionIcon() {
|
||||
switch (permission) {
|
||||
case Permission.camera:
|
||||
return Icons.camera_alt;
|
||||
case Permission.microphone:
|
||||
return Icons.mic;
|
||||
case Permission.location:
|
||||
return Icons.location_on;
|
||||
case Permission.storage:
|
||||
return Icons.storage;
|
||||
case Permission.photos:
|
||||
return Icons.photo_library;
|
||||
default:
|
||||
return Icons.security;
|
||||
}
|
||||
}
|
||||
|
||||
void _showSettingsDialog(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('权限设置'),
|
||||
content: const Text('请在设置中手动开启所需权限'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
openAppSettings();
|
||||
},
|
||||
child: const Text('去设置'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 分享操作表 (`src/sharing/share_action_sheet.dart`)
|
||||
|
||||
```dart
|
||||
class ShareActionSheet extends StatelessWidget {
|
||||
final ShareContent content;
|
||||
final List<SharePlatform> platforms;
|
||||
final Function(SharePlatform)? onPlatformSelected;
|
||||
|
||||
const ShareActionSheet({
|
||||
Key? key,
|
||||
required this.content,
|
||||
required this.platforms,
|
||||
this.onPlatformSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_buildHandle(),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'分享到',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildPlatformGrid(context),
|
||||
const SizedBox(height: 20),
|
||||
_buildMoreActions(context),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlatformGrid(BuildContext context) {
|
||||
return GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
childAspectRatio: 1,
|
||||
crossAxisSpacing: 20,
|
||||
mainAxisSpacing: 20,
|
||||
),
|
||||
itemCount: platforms.length,
|
||||
itemBuilder: (context, index) {
|
||||
final platform = platforms[index];
|
||||
return _buildPlatformItem(context, platform);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPlatformItem(BuildContext context, SharePlatform platform) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
onPlatformSelected?.call(platform);
|
||||
_shareToplatform(platform);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: platform.color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(
|
||||
platform.icon,
|
||||
color: platform.color,
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
platform.name,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _shareToplatform(SharePlatform platform) async {
|
||||
try {
|
||||
switch (platform.type) {
|
||||
case SharePlatformType.system:
|
||||
await Share.share(content.text, subject: content.title);
|
||||
break;
|
||||
case SharePlatformType.wechat:
|
||||
// 微信分享逻辑
|
||||
break;
|
||||
case SharePlatformType.weibo:
|
||||
// 微博分享逻辑
|
||||
break;
|
||||
case SharePlatformType.qq:
|
||||
// QQ分享逻辑
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
ToastUtils.showError('分享失败: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 工具类
|
||||
|
||||
### Toast工具类 (`src/utils/toast_utils.dart`)
|
||||
|
||||
```dart
|
||||
class ToastUtils {
|
||||
static void showSuccess(String message) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.green,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
static void showError(String message) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.red,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
static void showInfo(String message) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.blue,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
static void showWarning(String message) {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.orange,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 基础使用
|
||||
```dart
|
||||
class BasicUIsExample extends StatefulWidget {
|
||||
@override
|
||||
_BasicUIsExampleState createState() => _BasicUIsExampleState();
|
||||
}
|
||||
|
||||
class _BasicUIsExampleState extends State<BasicUIsExample> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initializeBasicUIs();
|
||||
}
|
||||
|
||||
Future<void> _initializeBasicUIs() async {
|
||||
await BasicUIs.initialize();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Basic UIs Example')),
|
||||
body: EnhancedRefreshIndicator(
|
||||
onRefresh: _handleRefresh,
|
||||
onLoadMore: _handleLoadMore,
|
||||
child: ListView(
|
||||
children: [
|
||||
// Lottie动画示例
|
||||
LottieAnimationWidget(
|
||||
assetPath: 'assets/animations/loading.json',
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
|
||||
// 权限请求示例
|
||||
ListTile(
|
||||
title: Text('请求相机权限'),
|
||||
onTap: () => _requestCameraPermission(),
|
||||
),
|
||||
|
||||
// 分享功能示例
|
||||
ListTile(
|
||||
title: Text('分享内容'),
|
||||
onTap: () => _showShareSheet(),
|
||||
),
|
||||
|
||||
// Toast示例
|
||||
ListTile(
|
||||
title: Text('显示Toast'),
|
||||
onTap: () => ToastUtils.showSuccess('操作成功'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleRefresh() async {
|
||||
await Future.delayed(Duration(seconds: 2));
|
||||
ToastUtils.showSuccess('刷新完成');
|
||||
}
|
||||
|
||||
Future<void> _handleLoadMore() async {
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
}
|
||||
|
||||
void _requestCameraPermission() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => PermissionRequestDialog(
|
||||
permission: Permission.camera,
|
||||
title: '相机权限',
|
||||
description: '需要相机权限来拍照和录制视频',
|
||||
rationale: '此权限用于扫描二维码和拍照功能',
|
||||
onGranted: () => ToastUtils.showSuccess('权限已授予'),
|
||||
onDenied: () => ToastUtils.showError('权限被拒绝'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showShareSheet() {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => ShareActionSheet(
|
||||
content: ShareContent(
|
||||
title: 'OneApp',
|
||||
text: '快来体验OneApp的强大功能!',
|
||||
url: 'https://oneapp.com',
|
||||
),
|
||||
platforms: [
|
||||
SharePlatform.system(),
|
||||
SharePlatform.wechat(),
|
||||
SharePlatform.weibo(),
|
||||
SharePlatform.qq(),
|
||||
],
|
||||
onPlatformSelected: (platform) {
|
||||
ToastUtils.showInfo('分享到${platform.name}');
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 组件优化
|
||||
- **懒加载**: 按需加载重型组件
|
||||
- **Widget缓存**: 缓存不变的Widget实例
|
||||
- **动画优化**: 合理使用动画避免过度渲染
|
||||
- **内存管理**: 及时释放资源和控制器
|
||||
|
||||
### 集成优化
|
||||
- **依赖管理**: 避免重复依赖和版本冲突
|
||||
- **包大小**: 优化资源文件减少包大小
|
||||
- **初始化**: 异步初始化避免阻塞启动
|
||||
- **缓存策略**: 合理使用缓存提升性能
|
||||
|
||||
## 测试策略
|
||||
|
||||
### Widget测试
|
||||
- **组件渲染测试**: 验证组件正确渲染
|
||||
- **交互测试**: 测试用户交互响应
|
||||
- **动画测试**: 测试动画效果
|
||||
- **权限测试**: 测试权限请求流程
|
||||
|
||||
### 集成测试
|
||||
- **模块集成测试**: 测试模块间协作
|
||||
- **第三方服务测试**: 测试外部服务集成
|
||||
- **性能测试**: 测试组件性能表现
|
||||
- **兼容性测试**: 测试平台兼容性
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 组件使用
|
||||
1. **统一入口**: 通过BasicUIs统一初始化
|
||||
2. **配置管理**: 集中管理组件配置
|
||||
3. **错误处理**: 完善的错误处理机制
|
||||
4. **用户体验**: 注重用户交互体验
|
||||
|
||||
### 开发规范
|
||||
1. **代码规范**: 遵循统一的代码规范
|
||||
2. **文档完善**: 提供详细的使用文档
|
||||
3. **版本管理**: 合理的版本发布策略
|
||||
4. **测试覆盖**: 保证充分的测试覆盖
|
||||
|
||||
## 总结
|
||||
|
||||
`basic_uis` 模块作为 OneApp 的通用UI组件集合,整合了丰富的UI功能组件和第三方服务,为应用开发提供了一站式的UI解决方案。通过统一的管理和标准化的接口,大大提升了开发效率和用户体验的一致性。模块具有良好的扩展性和可维护性,能够适应不断变化的UI需求。
|
||||
446
basic_uis/general_ui_component.md
Normal file
446
basic_uis/general_ui_component.md
Normal file
@@ -0,0 +1,446 @@
|
||||
# General UI Component 通用UI组件模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`general_ui_component` 是 OneApp 基础UI模块群中的通用UI组件模块,专门提供可复用的通用界面组件。该模块实现了通用的项目组件和分享对话框等核心功能。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: general_ui_component
|
||||
- **版本**: 0.0.1
|
||||
- **描述**: 通用UI组件库
|
||||
- **Flutter 版本**: >=1.17.0
|
||||
|
||||
## 核心组件
|
||||
|
||||
### 1. 项目组件 (ItemAComponent)
|
||||
|
||||
基于真实项目代码的通用项目展示组件:
|
||||
|
||||
```dart
|
||||
/// 通用项目组件A,用于显示带图标和标题的项目
|
||||
class ItemAComponent extends StatelessWidget {
|
||||
/// Logo图片URL
|
||||
String logoImg = '';
|
||||
|
||||
/// 标题文本
|
||||
String title = '';
|
||||
|
||||
/// 点击回调函数
|
||||
OnItemAClick onItemAClick;
|
||||
|
||||
/// 项目索引
|
||||
int index;
|
||||
|
||||
/// 自定义尺寸(可选)
|
||||
double? size;
|
||||
|
||||
ItemAComponent({
|
||||
required this.title,
|
||||
required this.logoImg,
|
||||
required this.onItemAClick,
|
||||
required this.index,
|
||||
this.size,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// 圆形背景
|
||||
Container(
|
||||
width: width(designWidgetWidth: 48),
|
||||
height: width(designWidgetWidth: 48),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: OneColors.bgcSub2,
|
||||
),
|
||||
),
|
||||
// 图标图片
|
||||
SizedBox(
|
||||
height: size ?? width(designWidgetWidth: 40),
|
||||
width: size ?? width(designWidgetWidth: 40),
|
||||
child: CacheImageComponent(
|
||||
imageUrl: logoImg,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 标题文本
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5.0),
|
||||
child: Text(
|
||||
title,
|
||||
style: OneTextStyle.content(
|
||||
color: const Color(0xFF7C7F81),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
onTap: () => onItemAClick(index),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 项目点击回调函数类型定义
|
||||
typedef OnItemAClick = Function(int index);
|
||||
```
|
||||
|
||||
### 2. 分享对话框 (ShareDialog)
|
||||
|
||||
基于真实项目代码的分享功能对话框:
|
||||
|
||||
```dart
|
||||
/// 分享对话框组件
|
||||
class Sharedialog extends StatelessWidget {
|
||||
/// 项目点击回调
|
||||
OnItemAClick onItemAClick;
|
||||
|
||||
/// 分享项目名称列表
|
||||
List<String> itemNameList;
|
||||
|
||||
/// 底部操作组件(可选)
|
||||
Widget? bottomActionWidget;
|
||||
|
||||
Sharedialog({
|
||||
required this.onItemAClick,
|
||||
required this.itemNameList,
|
||||
this.bottomActionWidget,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (itemNameList.isNotEmpty) {
|
||||
List<Widget> itemWidgetList = [];
|
||||
|
||||
for (int i = 0; i < itemNameList.length; i++) {
|
||||
// 添加间距
|
||||
if (bottomActionWidget != null) {
|
||||
itemWidgetList.add(SizedBox(
|
||||
width: width(designWidgetWidth: 36),
|
||||
));
|
||||
}
|
||||
|
||||
// 根据类型创建不同的分享项目
|
||||
switch (itemNameList[i]) {
|
||||
case 'weibo':
|
||||
itemWidgetList.add(_createShareItem(
|
||||
title: BasicUisIntlDelegate.current.Weibo,
|
||||
logoImg: 'packages/basic_uis/assets/icon/weibo.png',
|
||||
index: i,
|
||||
));
|
||||
break;
|
||||
case 'weixin':
|
||||
itemWidgetList.add(_createShareItem(
|
||||
title: BasicUisIntlDelegate.current.WeChat,
|
||||
logoImg: 'packages/basic_uis/assets/icon/wechat.png',
|
||||
index: i,
|
||||
));
|
||||
break;
|
||||
case 'friends':
|
||||
itemWidgetList.add(_createShareItem(
|
||||
title: BasicUisIntlDelegate.current.FriendCircle,
|
||||
logoImg: 'packages/basic_uis/assets/icon/moments.png',
|
||||
index: i,
|
||||
));
|
||||
break;
|
||||
case 'copy':
|
||||
itemWidgetList.add(_createShareItem(
|
||||
title: BasicUisIntlDelegate.current.copyLink,
|
||||
logoImg: 'packages/basic_uis/assets/icon/copy_link.png',
|
||||
index: i,
|
||||
size: width(designWidgetWidth: 20),
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
child: Wrap(
|
||||
children: itemWidgetList,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Container();
|
||||
}
|
||||
|
||||
/// 创建分享项目组件
|
||||
Widget _createShareItem({
|
||||
required String title,
|
||||
required String logoImg,
|
||||
required int index,
|
||||
double? size,
|
||||
}) {
|
||||
return ItemAComponent(
|
||||
title: title,
|
||||
logoImg: logoImg,
|
||||
index: index,
|
||||
size: size,
|
||||
onItemAClick: (int index) => onItemAClick(index),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
|
||||
基于实际项目结构:
|
||||
|
||||
```
|
||||
lib/
|
||||
├── ItemAComponent.dart # 通用项目组件
|
||||
└── share/ # 分享功能相关
|
||||
├── dialog/ # 分享对话框
|
||||
│ └── ShareDialog.dart # 分享对话框实现
|
||||
└── util/ # 分享工具类
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
基于实际项目依赖:
|
||||
|
||||
```dart
|
||||
// 国际化支持
|
||||
import 'package:basic_uis/generated/l10n.dart';
|
||||
import 'package:basic_utils/generated/l10n.dart';
|
||||
|
||||
// UI基础组件
|
||||
import 'package:ui_basic/ui_basic.dart';
|
||||
|
||||
// 基础工具
|
||||
import 'package:basic_utils/basic_utils.dart';
|
||||
|
||||
// 缓存图片组件
|
||||
import 'package:basic_uis/src/common_components/cache_image_component.dart';
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 1. ItemAComponent 使用示例
|
||||
|
||||
```dart
|
||||
import 'package:general_ui_component/ItemAComponent.dart';
|
||||
|
||||
class ServiceGridPage extends StatelessWidget {
|
||||
final List<ServiceItem> services = [
|
||||
ServiceItem('充电服务', 'assets/icons/charging.png'),
|
||||
ServiceItem('维修保养', 'assets/icons/maintenance.png'),
|
||||
ServiceItem('道路救援', 'assets/icons/rescue.png'),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('服务中心')),
|
||||
body: GridView.builder(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisSpacing: 16.0,
|
||||
mainAxisSpacing: 16.0,
|
||||
),
|
||||
itemCount: services.length,
|
||||
itemBuilder: (context, index) {
|
||||
final service = services[index];
|
||||
return ItemAComponent(
|
||||
title: service.name,
|
||||
logoImg: service.iconUrl,
|
||||
index: index,
|
||||
onItemAClick: _handleServiceClick,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleServiceClick(int index) {
|
||||
final service = services[index];
|
||||
print('选择了服务: ${service.name}');
|
||||
// 处理服务选择逻辑
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceItem {
|
||||
final String name;
|
||||
final String iconUrl;
|
||||
|
||||
ServiceItem(this.name, this.iconUrl);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. ShareDialog 分享功能使用
|
||||
|
||||
```dart
|
||||
import 'package:general_ui_component/share/dialog/ShareDialog.dart';
|
||||
|
||||
class ShareExample extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ElevatedButton(
|
||||
onPressed: () => _showShareDialog(context),
|
||||
child: Text('分享内容'),
|
||||
);
|
||||
}
|
||||
|
||||
void _showShareDialog(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => Sharedialog(
|
||||
itemNameList: ['weixin', 'friends', 'weibo', 'copy'],
|
||||
onItemAClick: _handleShareAction,
|
||||
bottomActionWidget: Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text('选择分享方式'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleShareAction(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
print('分享到微信');
|
||||
break;
|
||||
case 1:
|
||||
print('分享到朋友圈');
|
||||
break;
|
||||
case 2:
|
||||
print('分享到微博');
|
||||
break;
|
||||
case 3:
|
||||
print('复制链接');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## 依赖配置
|
||||
|
||||
### pubspec.yaml 关键依赖
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
# 国际化支持
|
||||
basic_uis:
|
||||
path: ../basic_uis
|
||||
|
||||
# 基础工具
|
||||
basic_utils:
|
||||
path: ../../oneapp_basic_utils/basic_utils
|
||||
|
||||
# UI基础组件
|
||||
ui_basic:
|
||||
path: ../ui_basic
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: any
|
||||
freezed: ^2.3.5
|
||||
flutter_lints: ^5.0.0
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 组件复用
|
||||
```dart
|
||||
// 推荐:创建配置化的服务列表
|
||||
Widget buildServiceGrid({
|
||||
required List<ServiceItem> services,
|
||||
required OnItemAClick onItemClick,
|
||||
}) {
|
||||
return GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.0,
|
||||
),
|
||||
itemCount: services.length,
|
||||
itemBuilder: (context, index) {
|
||||
final service = services[index];
|
||||
return ItemAComponent(
|
||||
title: service.name,
|
||||
logoImg: service.iconUrl,
|
||||
index: index,
|
||||
onItemAClick: onItemClick,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 分享功能集成
|
||||
```dart
|
||||
// 推荐:封装分享功能
|
||||
class ShareHelper {
|
||||
static void showShareDialog(
|
||||
BuildContext context,
|
||||
String content, {
|
||||
List<String> platforms = const ['weixin', 'friends', 'weibo', 'copy'],
|
||||
}) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => Sharedialog(
|
||||
itemNameList: platforms,
|
||||
onItemAClick: (index) => _handleShare(context, content, platforms[index]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static void _handleShare(BuildContext context, String content, String platform) {
|
||||
// 实际分享逻辑实现
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 主题适配
|
||||
```dart
|
||||
// 推荐:支持主题切换
|
||||
ItemAComponent(
|
||||
title: service.name,
|
||||
logoImg: service.iconUrl,
|
||||
index: index,
|
||||
onItemAClick: onItemClick,
|
||||
// 自动适配当前主题
|
||||
)
|
||||
```
|
||||
|
||||
## 项目集成
|
||||
|
||||
### 模块依赖关系
|
||||
|
||||
```dart
|
||||
// 实际项目中的依赖导入
|
||||
import 'package:basic_uis/generated/l10n.dart'; // 国际化
|
||||
import 'package:basic_utils/basic_utils.dart'; // 工具类
|
||||
import 'package:ui_basic/ui_basic.dart'; // UI基础
|
||||
import 'package:flutter/material.dart'; // Flutter核心
|
||||
```
|
||||
|
||||
### 使用建议
|
||||
|
||||
1. **性能优化**:使用`const`构造函数优化重建性能
|
||||
2. **内存管理**:及时释放不用的控制器和监听器
|
||||
3. **主题一致性**:使用OneColors主题颜色系统
|
||||
4. **国际化支持**:使用BasicUisIntlDelegate进行文本国际化
|
||||
|
||||
## 总结
|
||||
|
||||
`general_ui_component` 模块提供了OneApp项目中的核心通用UI组件,包括:
|
||||
|
||||
- **ItemAComponent**: 通用项目展示组件,支持圆形图标和文本标题
|
||||
- **ShareDialog**: 分享功能对话框,支持微信、朋友圈、微博、复制等分享方式
|
||||
- **完整的依赖管理**: 与OneApp其他模块的良好集成
|
||||
- **国际化支持**: 完整的中英文多语言支持
|
||||
|
||||
这些组件为OneApp提供了统一的UI设计语言和交互模式,确保了应用界面的一致性和可维护性。
|
||||
407
basic_uis/ui_basic.md
Normal file
407
basic_uis/ui_basic.md
Normal file
@@ -0,0 +1,407 @@
|
||||
# UI Basic 基础UI组件模块
|
||||
|
||||
## 模块概述
|
||||
|
||||
`ui_basic` 是 OneApp 基础UI模块群中的核心组件库,提供了应用开发中常用的基础UI组件和交互元素。该模块封装了通用的界面组件、布局容器、表单元素等,为整个应用提供统一的设计语言和用户体验。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: ui_basic
|
||||
- **版本**: 0.2.45
|
||||
- **仓库**: https://gitlab-rd0.maezia.com/dssomobile/oneapp/dssomobile-oneapp-ui-basic
|
||||
- **Flutter 版本**: >=1.17.0
|
||||
- **Dart 版本**: >=2.17.0 <4.0.0
|
||||
- **发布服务器**: http://175.24.250.68:4000/
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
基于实际项目的UI组件库,包含丰富的组件和第三方集成。
|
||||
|
||||
1. **基础组件库**
|
||||
- 按钮组件(OneIconButton、CommonButton)
|
||||
- 输入组件(BasicTextField、BasicMultiTextField、VehiclePlateField)
|
||||
- 展示组件(OneTag、OneCard、ProgressWidget)
|
||||
- 导航组件(CommonTitleBar、CommonTabbar)
|
||||
|
||||
2. **交互组件**
|
||||
- 上拉下拉刷新(pull_to_refresh集成)
|
||||
- 轮播图组件(OneSwiper、carousel_slider集成)
|
||||
- 对话框和弹窗(OneDialogX、CommonBottomSheet)
|
||||
- 加载指示器(LoadingWidget、CommonLoadingWidget)
|
||||
|
||||
3. **多媒体组件**
|
||||
- 图片组件(GlinettImage、ImageWidget、CachedNetworkImage集成)
|
||||
- 扫码组件(QrScannerWidget、flutter_scankit集成)
|
||||
- 相机组件(CameraWidget、camera集成)
|
||||
- SVG支持(flutter_svg集成)
|
||||
|
||||
4. **富文本和图表**
|
||||
- HTML富文本渲染(flutter_html集成)
|
||||
- 图表组件(OneChart、fl_chart集成)
|
||||
- ECharts集成(FlutterEcharts)
|
||||
- 评分组件(RatingWidget、flutter_rating_bar集成)
|
||||
|
||||
## 技术架构
|
||||
|
||||
### 目录结构
|
||||
```
|
||||
lib/
|
||||
├── ui_basic.dart # 模块入口文件
|
||||
├── src/ # 源代码目录
|
||||
│ ├── components/ # 基础组件
|
||||
│ ├── containers/ # 布局容器
|
||||
│ ├── interactions/ # 交互组件
|
||||
│ ├── themes/ # 主题配置
|
||||
│ ├── utils/ # 工具类
|
||||
│ └── constants/ # 常量定义
|
||||
├── widgets/ # 组件导出
|
||||
└── themes/ # 主题文件
|
||||
```
|
||||
|
||||
### 依赖关系
|
||||
|
||||
基于实际项目的pubspec.yaml配置,展示真实的依赖架构。
|
||||
|
||||
#### 框架依赖
|
||||
```yaml
|
||||
# 核心框架依赖
|
||||
dependencies:
|
||||
basic_network: ^0.2.3+4 # 网络通信基础
|
||||
basic_modular: ^0.2.3 # 模块化框架
|
||||
basic_modular_route: ^0.2.1 # 路由管理
|
||||
basic_intl_flutter: ^0.2.2+1 # 国际化支持
|
||||
basic_theme_core: ^0.2.5 # 主题核心
|
||||
ui_basic_annotation: ^0.2.0 # UI框架注解
|
||||
```
|
||||
|
||||
#### UI和交互依赖
|
||||
```yaml
|
||||
# UI组件和交互依赖
|
||||
dependencies:
|
||||
provider: ^6.0.5 # 状态管理
|
||||
flutter_html: ^3.0.0-beta.2 # HTML富文本渲染
|
||||
badges: ^3.1.1 # 角标组件
|
||||
pull_to_refresh: ^2.0.0 # 上拉下拉刷新
|
||||
carousel_slider: ^4.2.1 # 轮播图组件
|
||||
cached_network_image: ^3.3.0 # 缓存网络图片
|
||||
flutter_svg: ^2.0.6 # SVG图片支持
|
||||
flutter_smart_dialog: ^4.9.1 # 智能对话框
|
||||
visibility_detector: ^0.4.0+2# 可见性检测
|
||||
fl_chart: ^0.x.x # 图表组件
|
||||
```
|
||||
|
||||
#### 多媒体和工具依赖
|
||||
```yaml
|
||||
# 多媒体和工具依赖
|
||||
dependencies:
|
||||
camera: ^0.10.5+2 # 相机功能
|
||||
image_picker: ^1.1.2 # 图片选择
|
||||
image_cropper: ^9.1.0 # 图片裁剪
|
||||
flutter_image_compress: ^2.0.3# 图片压缩
|
||||
flutter_scankit: 2.0.3+1 # 扫码工具
|
||||
url_launcher: ^6.1.11 # URL跳转
|
||||
flutter_rating_bar: ^4.0.1 # 评分组件
|
||||
sprintf: ^7.0.0 # 字符串格式化
|
||||
dartz: ^0.10.1 # 函数式编程
|
||||
rxdart: ^0.27.7 # 响应式编程
|
||||
```
|
||||
|
||||
## 核心组件分析
|
||||
|
||||
### 1. 模块入口 (`ui_basic.dart`)
|
||||
|
||||
基于真实项目的模块导出结构,包含大量第三方库集成和自定义组件。
|
||||
|
||||
**功能职责**:
|
||||
- 统一导出所有UI组件和第三方库
|
||||
- 集成badge、cached_network_image、flutter_html等核心UI库
|
||||
- 导出自定义组件如OneColors、OneTextStyle、OneIcons
|
||||
- 提供car_func_block等车辆相关UI组件
|
||||
|
||||
```dart
|
||||
// 实际的模块导出结构(ui_basic.dart)
|
||||
library ui_basic;
|
||||
|
||||
// 第三方UI库集成
|
||||
export 'package:badges/badges.dart';
|
||||
export 'package:cached_network_image/cached_network_image.dart';
|
||||
export 'package:flutter_html/flutter_html.dart';
|
||||
export 'package:flutter_svg/flutter_svg.dart';
|
||||
export 'package:visibility_detector/visibility_detector.dart';
|
||||
export 'package:bottom_sheet/bottom_sheet.dart';
|
||||
export 'package:fl_chart/fl_chart.dart';
|
||||
|
||||
// 自定义组件导出
|
||||
export 'src/colors/colors.dart' show OneColors;
|
||||
export 'src/fonts/fonts.dart' show OneTextStyle, TextFont, OneBasicText;
|
||||
export 'src/icon/icon.dart' show OneIcons;
|
||||
|
||||
// UI组件导出
|
||||
export 'src/components/appbar/common_title_bar.dart';
|
||||
export 'src/components/button/buttons.dart';
|
||||
export 'src/components/dialog/dialog_export.dart';
|
||||
export 'src/components/loading/loading_widget.dart';
|
||||
export 'src/components/text_field/basic_text_field.dart';
|
||||
export 'src/components/cards/cards_export.dart';
|
||||
|
||||
// 车辆功能组件
|
||||
export 'src/car_func_block/car_func_block_class.dart';
|
||||
export 'src/car_func_block/car_func_block_manager.dart';
|
||||
|
||||
// 工具类导出
|
||||
export 'src/utils/qr_scanner_util/qr_scanner_util.dart';
|
||||
export 'src/utils/image_util/image_util.dart';
|
||||
export 'src/utils/launcher/launch_util.dart';
|
||||
```
|
||||
|
||||
### 2. 主题颜色系统 (`src/colors/colors.dart`)
|
||||
|
||||
基于主题核心框架的动态颜色系统,支持主题切换和自定义颜色。
|
||||
|
||||
```dart
|
||||
// 实际的颜色系统实现
|
||||
class OneColors {
|
||||
/// 主题色 Primary Color
|
||||
static Color get primary =>
|
||||
theme.ofStandard().themeData?.appColors?.primary ??
|
||||
const Color(0xFFEED484);
|
||||
|
||||
/// 背景色 Bgc
|
||||
static Color get bgc =>
|
||||
theme.ofStandard().themeData?.appColors?.backgroundColors.bgc ??
|
||||
const Color(0xFFFFFFFF);
|
||||
|
||||
/// 背景色 辅助1-5
|
||||
static Color get bgcSub1 =>
|
||||
theme.ofStandard().themeData?.appColors?.backgroundColors.bgcSub1 ??
|
||||
const Color(0xFFFFFFFF);
|
||||
// ... 更多背景色变体
|
||||
|
||||
/// 动态主题获取
|
||||
static ITheme get theme => uiBasicPlatformInfoDeps.theme != null
|
||||
? uiBasicPlatformInfoDeps.theme!
|
||||
: DefaultTheme(
|
||||
DefaultStandardResource(),
|
||||
DefaultUiKitResource(),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 按钮组件 (`src/components/button/buttons.dart`)
|
||||
|
||||
基于真实项目的按钮组件实现,支持多种按钮类型和状态管理。
|
||||
|
||||
```dart
|
||||
// 实际的按钮状态枚举
|
||||
enum BtnLoadingStatus {
|
||||
/// 初始化
|
||||
idle,
|
||||
/// 加载中
|
||||
loading,
|
||||
}
|
||||
|
||||
/// 按钮类型枚举
|
||||
enum BtnType {
|
||||
/// TextButton
|
||||
text,
|
||||
/// ElevatedButton
|
||||
elevated,
|
||||
/// OutlineButton
|
||||
outline,
|
||||
}
|
||||
|
||||
/// 实际的图标按钮组件
|
||||
class OneIconButton extends StatelessWidget {
|
||||
const OneIconButton({
|
||||
required this.child,
|
||||
this.iconSize,
|
||||
this.cubit,
|
||||
this.onPress,
|
||||
this.style,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// 按钮内容
|
||||
final Widget child;
|
||||
/// 字体大小
|
||||
final double? iconSize;
|
||||
/// 状态管理
|
||||
final OneIconButtonCubit? cubit;
|
||||
/// 点击回调
|
||||
final VoidCallback? onPress;
|
||||
/// 样式配置
|
||||
final ButtonStyle? style;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// 实际的按钮实现逻辑
|
||||
// 支持状态管理和样式定制
|
||||
}
|
||||
}
|
||||
|
||||
/// 通用按钮组件
|
||||
class CommonButton extends StatelessWidget {
|
||||
// 支持加载状态、不同按钮类型、自定义样式等
|
||||
// 集成BLoC状态管理和主题系统
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 文本输入组件 (`src/components/text_field/`)
|
||||
|
||||
包含多种文本输入组件的真实实现。
|
||||
|
||||
```dart
|
||||
// 基础文本输入字段
|
||||
export 'src/components/text_field/basic_text_field.dart';
|
||||
export 'src/components/text_field/basic_multi_text_field.dart';
|
||||
export 'src/components/text_field/clear_text_field.dart';
|
||||
export 'src/components/text_field/edit_text/edit_text.dart';
|
||||
|
||||
// 特殊用途文本字段
|
||||
export 'src/components/text_field/vehicle_plate_field/vehicle_plate_field_widget.dart';
|
||||
|
||||
// 实际支持的功能:
|
||||
// - 基础文本输入
|
||||
// - 多行文本输入
|
||||
// - 带清除按钮的文本输入
|
||||
// - 车牌号输入专用组件
|
||||
// - 集成表单验证和状态管理
|
||||
```
|
||||
|
||||
### 7. 第三方UI库集成
|
||||
|
||||
ui_basic模块集成了大量优秀的第三方UI库,提供开箱即用的功能。
|
||||
|
||||
```dart
|
||||
// 图标和标记组件
|
||||
export 'package:badges/badges.dart'; // 角标组件
|
||||
export 'package:font_awesome_flutter/font_awesome_flutter.dart'; // FontAwesome图标
|
||||
|
||||
// 图片和多媒体
|
||||
export 'package:cached_network_image/cached_network_image.dart'; // 缓存网络图片
|
||||
export 'package:flutter_svg/flutter_svg.dart'; // SVG支持
|
||||
export 'package:dd_js_util/dd_js_util.dart'; // 九宫格图片选择
|
||||
|
||||
// 富文本和格式化
|
||||
export 'package:flutter_html/flutter_html.dart'; // HTML渲染
|
||||
export 'package:sprintf/sprintf.dart'; // 字符串格式化
|
||||
export 'package:auto_size_text/auto_size_text.dart'; // 自适应文本
|
||||
|
||||
// 交互组件
|
||||
export 'package:bottom_sheet/bottom_sheet.dart'; // 底部弹出框
|
||||
export 'package:visibility_detector/visibility_detector.dart'; // 可见性检测
|
||||
export 'package:extended_tabs/extended_tabs.dart'; // 扩展Tab组件
|
||||
|
||||
// 图表组件
|
||||
export 'package:fl_chart/fl_chart.dart'; // Flutter图表库
|
||||
|
||||
// 轮播组件
|
||||
export 'package:flutter_swiper_null_safety_flutter3/flutter_swiper_null_safety_flutter3.dart';
|
||||
```
|
||||
|
||||
### 8. 工具类组件 (`src/utils/`)
|
||||
|
||||
丰富的工具类支持,涵盖图片处理、扫码、启动器等功能。
|
||||
|
||||
```dart
|
||||
// 图片相关工具
|
||||
export 'src/utils/image_util/image_util.dart';
|
||||
export 'src/utils/image_solution/image_solution_tools.dart';
|
||||
export 'src/utils/image_cropper_util/nativate_image_cropper.dart';
|
||||
|
||||
// 扫码相关
|
||||
export 'src/utils/qr_processor/qr_processor.dart';
|
||||
export 'src/utils/qr_scanner_util/qr_scanner_util.dart';
|
||||
|
||||
// 系统交互
|
||||
export 'src/utils/launcher/launch_util.dart'; // URL启动器
|
||||
export 'src/utils/imm/custom_imm.dart'; // 输入法管理
|
||||
|
||||
// 订单管理
|
||||
export 'src/utils/order_category_manager/order_category_factory.dart';
|
||||
export 'src/utils/order_category_manager/order_category_manager.dart';
|
||||
|
||||
// 其他工具
|
||||
export 'src/utils/keep_alive.dart'; // KeepAlive包装器
|
||||
export 'src/utils/widget_utils.dart'; // Widget工具类
|
||||
export 'src/utils/methods.dart' show formatDate; // 格式化方法
|
||||
```
|
||||
|
||||
### 9. 特色组件
|
||||
|
||||
针对OneApp应用特点开发的专用组件。
|
||||
|
||||
```dart
|
||||
// 车牌号相关
|
||||
export 'src/components/one_license_plate_number/one_license_plate_number.dart';
|
||||
export 'src/components/text_field/vehicle_plate_field/vehicle_plate_field_widget.dart';
|
||||
|
||||
// 车辆HVAC相关
|
||||
export 'src/components/widgets/car_hvac_other_widget.dart';
|
||||
|
||||
// 香氛组件
|
||||
export 'src/components/fragrance/fragrance_widget.dart';
|
||||
|
||||
// 步进器组件
|
||||
export 'src/components/stepper/stepper_widget.dart';
|
||||
|
||||
// 验证码组件
|
||||
export 'src/components/verification_code/verification_box.dart';
|
||||
export 'src/components/verification_code/code_widget.dart';
|
||||
|
||||
// 时间选择器
|
||||
export 'src/components/time_picker/common_time_picker.dart';
|
||||
export 'src/components/time_picker/ym_time_picker.dart';
|
||||
|
||||
// 可扩展GridView
|
||||
export 'src/components/gridview/expandable_gridview.dart';
|
||||
|
||||
// 瀑布流ScrollView
|
||||
export 'src/components/widgets/staggered_scrollview_widget.dart';
|
||||
export 'src/components/widgets/reorderable_staggered_scroll_view_widget.dart';
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 组件优化策略
|
||||
- **Widget缓存**: 缓存不变的Widget实例
|
||||
- **局部更新**: 使用Consumer精确控制更新范围
|
||||
- **延迟构建**: 使用Builder延迟构建复杂组件
|
||||
- **内存管理**: 及时释放资源和控制器
|
||||
|
||||
### 渲染优化
|
||||
- **RepaintBoundary**: 隔离重绘区域
|
||||
- **ListView.builder**: 使用懒加载列表
|
||||
- **Image优化**: 合理使用缓存和压缩
|
||||
- **动画优化**: 使用硬件加速动画
|
||||
|
||||
## 测试策略
|
||||
|
||||
### Widget测试
|
||||
- **组件渲染测试**: 验证组件正确渲染
|
||||
- **交互测试**: 测试用户交互响应
|
||||
- **主题测试**: 验证主题正确应用
|
||||
- **响应式测试**: 测试不同屏幕尺寸适配
|
||||
|
||||
### 单元测试
|
||||
- **工具类测试**: 测试工具方法功能
|
||||
- **状态管理测试**: 测试状态变化逻辑
|
||||
- **数据模型测试**: 测试数据序列化
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 组件设计原则
|
||||
1. **单一职责**: 每个组件功能单一明确
|
||||
2. **可复用性**: 设计通用的可复用组件
|
||||
3. **可配置性**: 提供丰富的配置选项
|
||||
4. **一致性**: 保持设计风格一致
|
||||
|
||||
### 使用建议
|
||||
1. **主题使用**: 优先使用主题颜色和样式
|
||||
2. **响应式设计**: 考虑不同屏幕尺寸适配
|
||||
3. **无障碍访问**: 添加语义标签和辅助功能
|
||||
4. **性能考虑**: 避免不必要的重建和重绘
|
||||
|
||||
## 总结
|
||||
|
||||
`ui_basic` 模块作为 OneApp 的基础UI组件库,提供了丰富的界面组件和交互元素。通过统一的设计语言、灵活的主题系统和完善的组件生态,为整个应用提供了一致的用户体验。模块具有良好的可扩展性和可维护性,能够满足各种界面开发需求。
|
||||
549
basic_uis/ui_business.md
Normal file
549
basic_uis/ui_business.md
Normal file
@@ -0,0 +1,549 @@
|
||||
# UI Business - 业务UI组件模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`ui_business` 是 OneApp 基础UI模块群中的业务UI组件库,提供与具体业务场景相关的UI组件和工具。该模块包含账户相关组件、订单相关组件、同意书组件等业务特定的界面元素和交互逻辑。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: ui_business
|
||||
- **模块路径**: oneapp_basic_uis/ui_business
|
||||
- **类型**: Flutter Package Module
|
||||
- **主要功能**: 业务UI组件、账户组件、订单组件、同意书组件
|
||||
|
||||
### 核心特性
|
||||
- **账户UI组件**: 提供登录、短信验证、证书拍照等账户相关UI
|
||||
- **订单UI组件**: 订单相关的业务界面组件
|
||||
- **同意书组件**: 用户协议和同意书相关UI
|
||||
- **国际化支持**: 支持中英文多语言
|
||||
- **表单验证**: 集成表单验证和数据处理
|
||||
- **路由守卫**: 业务路由保护和权限控制
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
ui_business/
|
||||
├── lib/
|
||||
│ ├── ui_account.dart # 账户相关组件导出
|
||||
│ ├── ui_order.dart # 订单相关组件导出
|
||||
│ ├── ui_consent.dart # 同意书相关组件导出
|
||||
│ ├── ui_common.dart # 通用业务组件导出
|
||||
│ ├── route_guard.dart # 路由守卫
|
||||
│ ├── customer_care.dart # 客服相关
|
||||
│ ├── poi_to_car.dart # POI到车功能
|
||||
│ ├── src/ # 源代码目录
|
||||
│ │ ├── ui_account/ # 账户相关组件
|
||||
│ │ │ ├── widgets/ # 账户UI组件
|
||||
│ │ │ │ ├── sms_auth/ # 短信验证组件
|
||||
│ │ │ │ ├── check_spin/ # 验证转动组件
|
||||
│ │ │ │ ├── certificates_photo/ # 证书拍照
|
||||
│ │ │ │ └── time_picker/ # 时间选择器
|
||||
│ │ │ ├── models/ # 账户数据模型
|
||||
│ │ │ ├── mgmt/ # 账户管理
|
||||
│ │ │ └── ui_config.dart # UI配置
|
||||
│ │ ├── ui_order/ # 订单相关组件
|
||||
│ │ └── constants/ # 常量定义
|
||||
│ ├── generated/ # 生成的国际化文件
|
||||
│ └── l10n/ # 国际化资源
|
||||
├── assets/ # 资源文件
|
||||
└── pubspec.yaml # 依赖配置
|
||||
```
|
||||
|
||||
## 核心架构组件
|
||||
|
||||
### 1. 短信验证组件 (SmsAuthWidget)
|
||||
|
||||
提供短信验证码输入和验证功能的完整UI组件:
|
||||
|
||||
```dart
|
||||
/// 短信验证组件
|
||||
class SmsAuthWidget extends StatelessWidget {
|
||||
/// 构造器
|
||||
///
|
||||
/// [verificationType] 验证码类型:1-登录注册 2-重置密码 3-设置/重置spin
|
||||
/// [callback] 事件回调
|
||||
/// [formKey] 表单键
|
||||
/// [onSubmitBtnLockChanged] 确认按钮锁定回调
|
||||
/// [smsCallbackOverride] 覆盖默认操作
|
||||
/// [lockPhoneEdit] 是否锁定手机号修改
|
||||
SmsAuthWidget({
|
||||
required this.verificationType,
|
||||
required this.formKey,
|
||||
required this.callback,
|
||||
required this.lockPhoneEdit,
|
||||
this.onSubmitBtnLockChanged,
|
||||
this.smsCallbackOverride,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// 默认超时时间
|
||||
static const defaultTimeout = 60;
|
||||
|
||||
/// 类型:1-登录注册 2-重置密码 3-设置/重置spin
|
||||
final String verificationType;
|
||||
|
||||
/// 表单键
|
||||
final SmsAuthFormKey formKey;
|
||||
|
||||
/// 结果回调
|
||||
final void Function(SmsAuthResult result) callback;
|
||||
|
||||
/// 确认按钮锁定状态变化回调
|
||||
final OnSubmitBtnLockChanged? onSubmitBtnLockChanged;
|
||||
|
||||
/// 短信校验覆盖回调
|
||||
final SmsCallbackOverride? smsCallbackOverride;
|
||||
|
||||
/// 是否锁定手机号修改
|
||||
final bool lockPhoneEdit;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocProvider(
|
||||
create: (ctx) => _bloc = SmsAuthBloc(smsCallbackOverride)
|
||||
..add(const SmsAuthEvent.getLocalProfile()),
|
||||
child: BlocConsumer<SmsAuthBloc, SmsAuthState>(
|
||||
listener: _pageListener,
|
||||
builder: _createLayout,
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 回调类型定义
|
||||
|
||||
```dart
|
||||
/// 确认按钮锁定状态变化回调
|
||||
typedef OnSubmitBtnLockChanged = void Function(bool locked);
|
||||
|
||||
/// 用于覆盖短信校验接口的回调
|
||||
typedef SmsCallbackOverride = Future<bool> Function(
|
||||
PhoneNumber phone,
|
||||
VerificationCode smsCode,
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 手机号掩码扩展
|
||||
|
||||
```dart
|
||||
extension _PhoneStringExtension on String {
|
||||
/// 手机号掩码显示,中间4位用*替换
|
||||
String get maskPhone {
|
||||
final buffer = StringBuffer();
|
||||
int i = 0;
|
||||
for (final c in characters) {
|
||||
if ([3, 4, 5, 6].contains(i)) {
|
||||
buffer.write('*');
|
||||
} else {
|
||||
buffer.write(c);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 通用项目组件 (ItemAComponent)
|
||||
|
||||
来自general_ui_component模块的通用组件:
|
||||
|
||||
```dart
|
||||
/// 通用项目组件A
|
||||
class ItemAComponent extends StatelessWidget {
|
||||
ItemAComponent({
|
||||
required this.title,
|
||||
required this.logoImg,
|
||||
required this.onItemAClick,
|
||||
required this.index,
|
||||
this.size,
|
||||
});
|
||||
|
||||
/// Logo图片URL
|
||||
String logoImg = '';
|
||||
|
||||
/// 标题文本
|
||||
String title = '';
|
||||
|
||||
/// 点击回调
|
||||
OnItemAClick onItemAClick;
|
||||
|
||||
/// 索引
|
||||
int index;
|
||||
|
||||
/// 自定义尺寸
|
||||
double? size;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
child: Column(
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: width(designWidgetWidth: 48),
|
||||
height: width(designWidgetWidth: 48),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: OneColors.bgcSub2,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: size ?? width(designWidgetWidth: 40),
|
||||
width: size ?? width(designWidgetWidth: 40),
|
||||
child: CacheImageComponent(
|
||||
imageUrl: logoImg,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5.0),
|
||||
child: Text(
|
||||
title,
|
||||
style: OneTextStyle.content(
|
||||
color: const Color(0xFF7C7F81),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
onTap: () => onItemAClick(index),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef OnItemAClick = Function(int index);
|
||||
```
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 1. 短信验证组件使用
|
||||
|
||||
```dart
|
||||
import 'package:ui_business/ui_account.dart';
|
||||
|
||||
class LoginPage extends StatefulWidget {
|
||||
@override
|
||||
_LoginPageState createState() => _LoginPageState();
|
||||
}
|
||||
|
||||
class _LoginPageState extends State<LoginPage> {
|
||||
late SmsAuthFormKey _formKey;
|
||||
bool _submitBtnLocked = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_formKey = SmsAuthFormKey();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('短信验证')),
|
||||
body: Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
SmsAuthWidget(
|
||||
verificationType: '1', // 登录注册类型
|
||||
formKey: _formKey,
|
||||
lockPhoneEdit: false,
|
||||
callback: _handleSmsResult,
|
||||
onSubmitBtnLockChanged: (locked) {
|
||||
setState(() {
|
||||
_submitBtnLocked = locked;
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _submitBtnLocked ? null : _handleSubmit,
|
||||
child: Text('确认'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleSmsResult(SmsAuthResult result) {
|
||||
switch (result.state) {
|
||||
case SmsAuthResultEnum.success:
|
||||
// 验证成功,处理登录逻辑
|
||||
print('验证成功,UUID: ${result.uuid}');
|
||||
Navigator.pushReplacementNamed(context, '/home');
|
||||
break;
|
||||
case SmsAuthResultEnum.failed:
|
||||
// 验证失败
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('验证失败,请重试')),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void _handleSubmit() {
|
||||
// 触发表单验证和提交
|
||||
_formKey.controllerList.forEach((controller) => controller());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 自定义短信验证回调
|
||||
|
||||
```dart
|
||||
// 自定义短信验证逻辑
|
||||
Future<bool> customSmsVerification(
|
||||
PhoneNumber phone,
|
||||
VerificationCode smsCode
|
||||
) async {
|
||||
try {
|
||||
// 调用自定义API进行验证
|
||||
final response = await MyApiService.verifySms(
|
||||
phone: phone.value,
|
||||
code: smsCode.value,
|
||||
);
|
||||
return response.success;
|
||||
} catch (e) {
|
||||
print('短信验证异常: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用自定义验证回调
|
||||
SmsAuthWidget(
|
||||
verificationType: '1',
|
||||
formKey: _formKey,
|
||||
lockPhoneEdit: false,
|
||||
callback: _handleSmsResult,
|
||||
smsCallbackOverride: customSmsVerification, // 使用自定义验证
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 通用组件列表使用
|
||||
|
||||
```dart
|
||||
import 'package:general_ui_component/ItemAComponent.dart';
|
||||
|
||||
class ServiceListPage extends StatelessWidget {
|
||||
final List<ServiceItem> services = [
|
||||
ServiceItem('充电服务', 'assets/images/charging.png'),
|
||||
ServiceItem('维修保养', 'assets/images/maintenance.png'),
|
||||
ServiceItem('道路救援', 'assets/images/rescue.png'),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('服务列表')),
|
||||
body: GridView.builder(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.0,
|
||||
crossAxisSpacing: 16.0,
|
||||
mainAxisSpacing: 16.0,
|
||||
),
|
||||
itemCount: services.length,
|
||||
itemBuilder: (context, index) {
|
||||
final service = services[index];
|
||||
return ItemAComponent(
|
||||
title: service.name,
|
||||
logoImg: service.iconUrl,
|
||||
index: index,
|
||||
onItemAClick: _handleServiceClick,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleServiceClick(int index) {
|
||||
final service = services[index];
|
||||
print('点击了服务: ${service.name}');
|
||||
// 处理服务点击逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 国际化支持
|
||||
|
||||
```dart
|
||||
import 'package:ui_business/generated/l10n.dart';
|
||||
|
||||
class LocalizedWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(S.of(context).smsVerificationPage_hint_code),
|
||||
Text(S.of(context).smsVerificationPage_btn_get),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖配置
|
||||
|
||||
### pubspec.yaml 关键依赖
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
# 基础UI组件
|
||||
ui_basic:
|
||||
path: ../ui_basic
|
||||
|
||||
# 基础工具
|
||||
basic_utils:
|
||||
path: ../../oneapp_basic_utils/basic_utils
|
||||
|
||||
# 模块化路由
|
||||
basic_modular:
|
||||
path: ../../oneapp_basic_utils/basic_modular
|
||||
|
||||
# 账户服务
|
||||
clr_account:
|
||||
path: ../../oneapp_account/clr_account
|
||||
|
||||
# 状态管理
|
||||
flutter_bloc: ^8.0.0
|
||||
|
||||
# 国际化
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
intl: ^0.17.0
|
||||
|
||||
dev_dependencies:
|
||||
# 国际化代码生成
|
||||
intl_utils: ^2.8.0
|
||||
```
|
||||
|
||||
## 国际化配置
|
||||
|
||||
### l10n/intl_zh.arb (中文)
|
||||
```json
|
||||
{
|
||||
"smsVerificationPage_hint_code": "请输入验证码",
|
||||
"smsVerificationPage_btn_get": "获取验证码",
|
||||
"smsVerificationsPage_error_invalidCode": "验证码格式不正确"
|
||||
}
|
||||
```
|
||||
|
||||
### l10n/intl_en.arb (英文)
|
||||
```json
|
||||
{
|
||||
"smsVerificationPage_hint_code": "Please enter verification code",
|
||||
"smsVerificationPage_btn_get": "Get Code",
|
||||
"smsVerificationsPage_error_invalidCode": "Invalid verification code format"
|
||||
}
|
||||
```
|
||||
|
||||
## 表单验证
|
||||
|
||||
### SmsAuthFormKey 使用
|
||||
|
||||
```dart
|
||||
class CustomFormPage extends StatefulWidget {
|
||||
@override
|
||||
_CustomFormPageState createState() => _CustomFormPageState();
|
||||
}
|
||||
|
||||
class _CustomFormPageState extends State<CustomFormPage> {
|
||||
late SmsAuthFormKey _formKey;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_formKey = SmsAuthFormKey();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
// 表单字段
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_formKey.validate()) {
|
||||
_formKey.save();
|
||||
// 使用表单数据
|
||||
print('手机号: ${_formKey.phone}');
|
||||
print('短信码: ${_formKey.sms}');
|
||||
}
|
||||
},
|
||||
child: Text('提交'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 错误处理
|
||||
```dart
|
||||
// 推荐:完整的错误处理
|
||||
void _handleSmsResult(SmsAuthResult result) {
|
||||
switch (result.state) {
|
||||
case SmsAuthResultEnum.success:
|
||||
// 成功处理
|
||||
_navigateToNextPage(result);
|
||||
break;
|
||||
case SmsAuthResultEnum.failed:
|
||||
// 失败处理,显示用户友好的错误信息
|
||||
_showErrorMessage('验证失败,请检查验证码是否正确');
|
||||
break;
|
||||
case SmsAuthResultEnum.timeout:
|
||||
// 超时处理
|
||||
_showErrorMessage('验证超时,请重新获取验证码');
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 资源管理
|
||||
```dart
|
||||
// 推荐:及时释放资源
|
||||
@override
|
||||
void dispose() {
|
||||
_formKey.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 无障碍支持
|
||||
```dart
|
||||
// 推荐:添加语义标签
|
||||
Semantics(
|
||||
label: '验证码输入框',
|
||||
hint: '请输入6位数字验证码',
|
||||
child: SmsAuthWidget(
|
||||
// 配置参数
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
## 问题排查
|
||||
|
||||
### 常见问题
|
||||
1. **验证码收不到**: 检查手机号格式和网络连接
|
||||
2. **倒计时不工作**: 确认CountDownButton状态管理正确
|
||||
3. **国际化文本不显示**: 检查l10n配置和S.of(context)使用
|
||||
|
||||
### 调试技巧
|
||||
- 使用Flutter Inspector查看Widget树
|
||||
- 检查BLoC状态变化日志
|
||||
- 验证表单验证逻辑
|
||||
|
||||
Reference in New Issue
Block a user