Flutter UI Components:闲来无事,设计整理了这几年来使用的UI组件库

本文详细介绍了一个完整的 Flutter UI 组件库的设计思路、架构实现和核心特性,包含 50+ 个高质量组件,支持主题切换、响应式设计等企业级功能。

📋 目录

🎯 项目概述

Flutter UI Components 是一个基于 Flutter 框架开发的企业级 UI 组件库,旨在为开发者提供一套完整、可定制、高性能的 UI 组件解决方案。

核心特性

  • 🎨 完整的主题系统:支持浅色/深色主题切换,自动适配系统主题
  • 📱 响应式设计:适配不同屏幕尺寸,支持平板和桌面端
  • 🔧 高度可定制:丰富的配置选项,满足各种设计需求
  • 性能优化:使用 const 构造函数,减少不必要的重建
  • 🧪 完整测试:单元测试和 Widget 测试覆盖
  • 🏗️ 模块化架构:清晰的目录结构,便于维护和扩展

组件统计

分类 组件数量 主要组件
按钮组件 5+ UIButton、UIGradientButton、UIHighlightButton
卡片组件 3+ UIDefaultCard、UICollectionView
导航组件 2+ UIAppBarDecorator、UISegmentedControl
反馈组件 8+ UIToolTip、UIToast、UIDialog、UISnackBar
数据展示 6+ UITagView、UIBadgeView、UIProgressIndicator
输入组件 4+ UITextField、UICheckBox、UIDropDownButton
布局组件 5+ UIListView、UIGridView、UITableView

🏗️ 系统架构设计

整体架构图

graph TB A[Flutter UI Components] --> B[Core Module 核心模块] A --> C[Components Module 组件模块] B --> D[Base Classes 基础类] B --> E[Theme System 主题系统] B --> F[Constants 常量定义] B --> G[Extensions 扩展方法] C --> H[Buttons 按钮组件] C --> I[Cards 卡片组件] C --> J[Navigation 导航组件] C --> K[Feedback 反馈组件] C --> L[Data Display 数据展示] C --> M[Input 输入组件] C --> N[Layout 布局组件] D --> O[BaseWidget] D --> P[BaseStatefulWidget] D --> Q[UIBasePage] E --> R[AppTheme] E --> S[ThemeConfig] E --> T[ThemeBuilder]

模块依赖关系

graph LR A[Components] --> B[Core] B --> C[Flutter Framework] D[BaseWidget] --> E[Theme System] D --> F[Constants] G[UI Components] --> D G --> H[Extensions] I[Example App] --> A I --> J[GetX State Management]

🔧 核心模块详解

1. 基础类设计

所有组件都继承自 BaseWidget,确保统一的接口和生命周期管理:

dart 复制代码
/// 基础Widget抽象类
/// 所有UI组件都应该继承此类,确保统一的接口和生命周期管理
abstract class BaseWidget extends StatelessWidget {
  const BaseWidget({super.key});

  /// 组件名称,用于调试和日志
  String get widgetName;

  /// 组件版本,用于版本管理
  String get version => '1.0.0';

  /// 是否启用调试模式
  bool get enableDebug => false;

  @override
  Widget build(BuildContext context) {
    if (enableDebug) {
      debugPrint('Building $widgetName v$version');
    }
    return buildWidget(context);
  }

  /// 子类需要实现的构建方法
  Widget buildWidget(BuildContext context);

  /// 获取组件的主题数据
  ThemeData getTheme(BuildContext context) {
    return Theme.of(context);
  }

  /// 获取组件的主题配置
  AppThemeConfig getThemeConfig(BuildContext context) {
    final theme = getTheme(context);
    return AppThemeConfig.fromBrightness(theme.brightness);
  }
}

2. 主题系统架构

主题系统采用接口抽象和配置分离的设计模式:

dart 复制代码
/// 主题配置接口
abstract class IThemeConfig {
  Color get primary;
  Color get secondary;
  Color get success;
  Color get error;
  Color get text;
  Color get background;
  Color get surface;
  // ... 更多颜色定义
}

/// 应用主题管理类
class AppTheme {
  static AppTheme? _instance;
  static AppTheme get instance => _instance ??= AppTheme._();

  /// 当前主题模式
  ThemeMode _themeMode = ThemeMode.system;

  /// 当前主题配置
  IThemeConfig? _customConfig;

  /// 主题配置构建器
  IThemeConfig Function(Brightness brightness)? _configBuilder;

  /// 获取当前主题配置
  IThemeConfig get currentConfig {
    if (_customConfig != null) {
      return _customConfig!;
    }

    if (_configBuilder != null) {
      final brightness = _themeMode == ThemeMode.dark
          ? Brightness.dark : Brightness.light;
      return _configBuilder!(brightness);
    }

    // 返回默认配置
    return _themeMode == ThemeMode.dark
        ? const DefaultDarkThemeConfig()
        : const DefaultThemeConfig();
  }

  /// 切换主题模式
  void switchTheme(ThemeMode mode) {
    if (_themeMode != mode) {
      _themeMode = mode;
      _notifyThemeListeners();
    }
  }
}

3. 常量系统设计

统一的常量管理确保设计一致性:

dart 复制代码
/// 应用常量定义
class AppConstants {
  // 间距常量
  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 double fontSizeXs = 12.0;
  static const double fontSizeSm = 14.0;
  static const double fontSizeMd = 16.0;
  static const double fontSizeLg = 18.0;
  static const double fontSizeXl = 20.0;

  // 动画时长常量
  static const int animationDurationFast = 200;
  static const int animationDurationMd = 300;
  static const int animationDurationSlow = 500;
}

🎨 组件分类与实现

1. 按钮组件

按钮组件支持多种类型、尺寸和状态:

dart 复制代码
/// 按钮类型枚举
enum UIButtonType {
  primary,    // 主要按钮
  secondary,  // 次要按钮
  success,    // 成功按钮
  warning,    // 警告按钮
  error,      // 错误按钮
  info,       // 信息按钮
  outline,    // 轮廓按钮
  text,       // 文本按钮
}

/// 通用按钮组件
class UIButton extends BaseWidget {
  const UIButton({
    super.key,
    required this.text,
    this.onPressed,
    this.type = UIButtonType.primary,
    this.size = UIButtonSize.medium,
    this.isLoading = false,
    this.isDisabled = false,
    this.icon,
    this.fullWidth = false,
  });

  final String text;
  final VoidCallback? onPressed;
  final UIButtonType type;
  final UIButtonSize size;
  final bool isLoading;
  final bool isDisabled;
  final IconData? icon;
  final bool fullWidth;

  @override
  String get widgetName => 'UIButton';

  @override
  Widget buildWidget(BuildContext context) {
    final themeConfig = getThemeConfig(context);
    final isEnabled = onPressed != null && !isDisabled && !isLoading;

    return SizedBox(
      width: fullWidth ? double.infinity : null,
      child: ElevatedButton(
        onPressed: isEnabled ? onPressed : null,
        style: _buildButtonStyle(themeConfig),
        child: _buildButtonContent(themeConfig),
      ),
    );
  }

  ButtonStyle _buildButtonStyle(AppThemeConfig config) {
    return ElevatedButton.styleFrom(
      backgroundColor: _getBackgroundColor(config),
      foregroundColor: _getForegroundColor(config),
      padding: _getPadding(),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(AppConstants.radiusSm),
      ),
      elevation: type == UIButtonType.outline ? 0 : 2,
    );
  }
}

2. 工具提示组件

工具提示组件支持多方向显示和丰富的自定义选项:

dart 复制代码
/// 工具提示方向枚举
enum UIToolTipDirection {
  up, down, left, right,
  upLeft, upRight, downLeft, downRight,
}

/// 工具提示配置
class UIToolTipConfig {
  const UIToolTipConfig({
    this.direction = UIToolTipDirection.down,
    this.distance = 8.0,
    this.arrowSize = 8.0,
    this.backgroundColor = Colors.black87,
    this.textColor = Colors.white,
    this.borderRadius = 8.0,
    this.padding = const EdgeInsets.all(12.0),
    this.showArrow = true,
    this.animationDuration = const Duration(milliseconds: 200),
  });

  final UIToolTipDirection direction;
  final double distance;
  final double arrowSize;
  final Color backgroundColor;
  final Color textColor;
  final double borderRadius;
  final EdgeInsets padding;
  final bool showArrow;
  final Duration animationDuration;
}

/// 主要的工具提示组件
class UIToolTip extends StatefulWidget {
  const UIToolTip({
    super.key,
    required this.content,
    this.config = const UIToolTipConfig(),
    this.controller,
    required this.child,
  });

  final Widget content;
  final UIToolTipConfig config;
  final UIToolTipController? controller;
  final Widget child;

  @override
  State<UIToolTip> createState() => _UIToolTipState();
}

3. 渐变色进度指示器

自定义绘制的渐变色圆形进度指示器:

dart 复制代码
/// 渐变色圆形进度指示器组件
class UIGradientCircularProgressIndicator extends StatelessWidget {
  const UIGradientCircularProgressIndicator({
    super.key,
    required this.radius,
    this.strokeWidth = 4.0,
    this.colors,
    this.stops,
    this.strokeCapRound = false,
    this.backgroundColor = const Color(0xFFEEEEEE),
    this.totalAngle = 2 * pi,
    this.value,
    this.animationDuration = const Duration(milliseconds: 300),
    this.child,
  });

  final double radius;
  final double strokeWidth;
  final List<Color>? colors;
  final List<double>? stops;
  final bool strokeCapRound;
  final Color backgroundColor;
  final double totalAngle;
  final double? value;
  final Duration animationDuration;
  final Widget? child;

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      size: Size(radius * 2, radius * 2),
      painter: _GradientCircularProgressPainter(
        strokeWidth: strokeWidth,
        colors: colors ?? [Theme.of(context).primaryColor],
        stops: stops,
        strokeCapRound: strokeCapRound,
        backgroundColor: backgroundColor,
        totalAngle: totalAngle,
        value: value,
      ),
      child: child,
    );
  }
}

class _GradientCircularProgressPainter extends CustomPainter {
  _GradientCircularProgressPainter({
    required this.strokeWidth,
    required this.colors,
    this.stops,
    required this.strokeCapRound,
    required this.backgroundColor,
    required this.totalAngle,
    this.value,
  });

  final double strokeWidth;
  final List<Color> colors;
  final List<double>? stops;
  final bool strokeCapRound;
  final Color backgroundColor;
  final double totalAngle;
  final double? value;

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    final radius = (size.width - strokeWidth) / 2;

    // 绘制背景圆环
    final backgroundPaint = Paint()
      ..color = backgroundColor
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke
      ..strokeCap = strokeCapRound ? StrokeCap.round : StrokeCap.butt;

    canvas.drawArc(
      Rect.fromCircle(center: center, radius: radius),
      -pi / 2,
      totalAngle,
      false,
      backgroundPaint,
    );

    // 绘制进度圆环
    if (value != null && value! > 0) {
      final progressPaint = Paint()
        ..strokeWidth = strokeWidth
        ..style = PaintingStyle.stroke
        ..strokeCap = strokeCapRound ? StrokeCap.round : StrokeCap.butt;

      if (colors.length == 1) {
        progressPaint.color = colors.first;
      } else {
        final gradient = SweepGradient(
          colors: colors,
          stops: stops,
        );
        progressPaint.shader = gradient.createShader(
          Rect.fromCircle(center: center, radius: radius),
        );
      }

      canvas.drawArc(
        Rect.fromCircle(center: center, radius: radius),
        -pi / 2,
        totalAngle * value!,
        false,
        progressPaint,
      );
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

🎨 主题系统设计

主题切换流程图

flowchart TD A[用户触发主题切换] --> B[AppTheme.switchTheme] B --> C[更新_themeMode] C --> D[通知主题监听器] D --> E[UI组件重新构建] E --> F[应用新主题样式] G[系统主题变化] --> H[监听系统主题] H --> I[自动切换主题模式] I --> B J[自定义主题配置] --> K[setCustomConfig] K --> L[更新_customConfig] L --> D

主题配置示例

dart 复制代码
/// 自定义主题配置示例
class CustomThemeConfig implements IThemeConfig {
  const CustomThemeConfig();

  @override
  Color get primary => const Color(0xFF6366F1); // 靛蓝色

  @override
  Color get secondary => const Color(0xFF8B5CF6); // 紫色

  @override
  Color get success => const Color(0xFF10B981); // 绿色

  @override
  Color get error => const Color(0xFFEF4444); // 红色

  @override
  Color get warning => const Color(0xFFF59E0B); // 橙色

  @override
  Color get info => const Color(0xFF3B82F6); // 蓝色

  @override
  Color get text => const Color(0xFF1F2937); // 深灰色

  @override
  Color get textSecondary => const Color(0xFF6B7280); // 中灰色

  @override
  Color get background => const Color(0xFFF9FAFB); // 浅灰色

  @override
  Color get surface => Colors.white;

  @override
  Color get divider => const Color(0xFFE5E7EB); // 分割线颜色

  @override
  Color get border => const Color(0xFFD1D5DB); // 边框颜色

  @override
  Color get disabled => const Color(0xFF9CA3AF); // 禁用颜色

  @override
  Color get disabledLight => const Color(0xFFF3F4F6); // 浅禁用颜色

  @override
  Color get tips => const Color(0xFFF59E0B); // 提示颜色

  @override
  Color get dialogText => const Color(0xFF1F2937); // 对话框文本

  @override
  Color get lightBlue => const Color(0xFFDBEAFE); // 浅蓝色

  @override
  Color get lighterBlue => const Color(0xFFEFF6FF); // 更浅蓝色

  @override
  Color get lightGray => const Color(0xFFF3F4F6); // 浅灰色
}

/// 使用自定义主题
void setupCustomTheme() {
  AppTheme.instance.setCustomConfig(const CustomThemeConfig());
}

⚡ 性能优化策略

1. 组件优化

dart 复制代码
/// 使用 const 构造函数优化
class UIButton extends BaseWidget {
  const UIButton({
    super.key,
    required this.text,
    this.onPressed,
    this.type = UIButtonType.primary,
    this.size = UIButtonSize.medium,
    this.isLoading = false,
    this.isDisabled = false,
    this.icon,
    this.fullWidth = false,
  });

  // 使用 const 构造函数可以避免不必要的重建
  static const UIButton primaryButton = UIButton(
    text: 'Primary',
    type: UIButtonType.primary,
  );
}

2. 列表优化

dart 复制代码
/// 使用 ListView.builder 优化长列表
class UIListView extends StatelessWidget {
  const UIListView({
    super.key,
    required this.itemCount,
    required this.itemBuilder,
    this.separatorBuilder,
    this.padding,
    this.physics,
  });

  final int itemCount;
  final Widget Function(BuildContext context, int index) itemBuilder;
  final Widget Function(BuildContext context, int index)? separatorBuilder;
  final EdgeInsetsGeometry? padding;
  final ScrollPhysics? physics;

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      padding: padding,
      physics: physics,
      itemCount: itemCount,
      itemBuilder: itemBuilder,
      separatorBuilder: separatorBuilder ?? (context, index) => const SizedBox.shrink(),
    );
  }
}

3. 动画优化

dart 复制代码
/// 使用 AnimationController 优化动画性能
class _UIToolTipState extends State<UIToolTip>
    with TickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      duration: widget.config.animationDuration,
      vsync: this,
    );
    _animation = CurvedAnimation(
      parent: _animationController,
      curve: Curves.easeInOut,
    );
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

🧪 测试与质量保证

1. 单元测试示例

dart 复制代码
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_ui_components/flutter_ui_components.dart';

void main() {
  group('UIButton Tests', () {
    testWidgets('应该渲染带有正确文本的按钮', (tester) async {
      // Arrange
      const buttonText = '测试按钮';

      // Act
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: UIButton(
              text: buttonText,
              onPressed: () {},
            ),
          ),
        ),
      );

      // Assert
      expect(find.text(buttonText), findsOneWidget);
    });

    testWidgets('禁用状态下按钮应该不可点击', (tester) async {
      // Arrange
      bool wasPressed = false;

      // Act
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: UIButton(
              text: '禁用按钮',
              onPressed: () => wasPressed = true,
              isDisabled: true,
            ),
          ),
        ),
      );

      await tester.tap(find.text('禁用按钮'));
      await tester.pump();

      // Assert
      expect(wasPressed, false);
    });

    testWidgets('加载状态下应该显示加载指示器', (tester) async {
      // Act
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: UIButton(
              text: '加载按钮',
              onPressed: () {},
              isLoading: true,
            ),
          ),
        ),
      );

      // Assert
      expect(find.byType(CircularProgressIndicator), findsOneWidget);
    });
  });
}

2. Widget 测试示例

dart 复制代码
void main() {
  group('UIToolTip Tests', () {
    testWidgets('应该显示工具提示内容', (tester) async {
      // Arrange
      const tooltipContent = '这是一个工具提示';

      // Act
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: UIToolTip(
              content: const Text(tooltipContent),
              child: const Text('悬停我'),
            ),
          ),
        ),
      );

      // 触发悬停
      await tester.longPress(find.text('悬停我'));
      await tester.pumpAndSettle();

      // Assert
      expect(find.text(tooltipContent), findsOneWidget);
    });

    testWidgets('应该根据配置显示箭头', (tester) async {
      // Act
      await tester.pumpWidget(
        MaterialApp(
          home: Scaffold(
            body: UIToolTip(
              content: const Text('带箭头的提示'),
              config: const UIToolTipConfig(showArrow: true),
              child: const Text('悬停我'),
            ),
          ),
        ),
      );

      await tester.longPress(find.text('悬停我'));
      await tester.pumpAndSettle();

      // Assert
      expect(find.byType(CustomPaint), findsWidgets);
    });
  });
}

📱 使用示例

1. 基础使用

dart 复制代码
import 'package:flutter/material.dart';
import 'package:flutter_ui_components/flutter_ui_components.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter UI Components Demo',
      theme: AppTheme.instance.lightTheme,
      darkTheme: AppTheme.instance.darkTheme,
      themeMode: AppTheme.instance.themeMode,
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('UI Components Demo'),
        actions: [
          IconButton(
            icon: const Icon(Icons.brightness_6),
            onPressed: () {
              // 切换主题
              final currentMode = AppTheme.instance.themeMode;
              final newMode = currentMode == ThemeMode.light
                  ? ThemeMode.dark
                  : ThemeMode.light;
              AppTheme.instance.switchTheme(newMode);
            },
          ),
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 按钮组件示例
            _buildSectionTitle('按钮组件'),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                UIButton(
                  text: '主要按钮',
                  onPressed: () => _showToast('主要按钮被点击'),
                  type: UIButtonType.primary,
                ),
                UIButton(
                  text: '成功按钮',
                  onPressed: () => _showToast('成功按钮被点击'),
                  type: UIButtonType.success,
                ),
                UIButton(
                  text: '警告按钮',
                  onPressed: () => _showToast('警告按钮被点击'),
                  type: UIButtonType.warning,
                ),
                UIButton(
                  text: '错误按钮',
                  onPressed: () => _showToast('错误按钮被点击'),
                  type: UIButtonType.error,
                ),
                UIButton(
                  text: '轮廓按钮',
                  onPressed: () => _showToast('轮廓按钮被点击'),
                  type: UIButtonType.outline,
                ),
                UIButton(
                  text: '文本按钮',
                  onPressed: () => _showToast('文本按钮被点击'),
                  type: UIButtonType.text,
                ),
              ],
            ),

            const SizedBox(height: 24),

            // 卡片组件示例
            _buildSectionTitle('卡片组件'),
            UIDefaultCard(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    '卡片标题',
                    style: TextStyle(
                      fontSize: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 8),
                  const Text('这是一个卡片组件的示例内容。'),
                  const SizedBox(height: 16),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      UIButton(
                        text: '取消',
                        type: UIButtonType.text,
                        onPressed: () {},
                      ),
                      const SizedBox(width: 8),
                      UIButton(
                        text: '确定',
                        onPressed: () {},
                      ),
                    ],
                  ),
                ],
              ),
            ),

            const SizedBox(height: 24),

            // 工具提示组件示例
            _buildSectionTitle('工具提示组件'),
            Center(
              child: UIToolTip(
                content: const Text('这是一个工具提示'),
                config: const UIToolTipConfig(
                  direction: UIToolTipDirection.down,
                  backgroundColor: Colors.black87,
                  textColor: Colors.white,
                ),
                child: UIButton(
                  text: '悬停查看提示',
                  onPressed: () {},
                ),
              ),
            ),

            const SizedBox(height: 24),

            // 进度指示器示例
            _buildSectionTitle('进度指示器'),
            Center(
              child: Column(
                children: [
                  UIGradientCircularProgressIndicator(
                    radius: 50,
                    value: 0.7,
                    colors: const [
                      Colors.blue,
                      Colors.purple,
                      Colors.pink,
                    ],
                    child: const Center(
                      child: Text(
                        '70%',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                  const SizedBox(height: 16),
                  UIProgressIndicator(
                    value: 0.6,
                    backgroundColor: Colors.grey[300]!,
                    valueColor: Colors.blue,
                  ),
                ],
              ),
            ),

            const SizedBox(height: 24),

            // 标签组件示例
            _buildSectionTitle('标签组件'),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                UITagView(
                  text: '默认标签',
                  onTap: () => _showToast('默认标签被点击'),
                ),
                UITagView(
                  text: '主要标签',
                  type: UITagType.primary,
                  onTap: () => _showToast('主要标签被点击'),
                ),
                UITagView(
                  text: '成功标签',
                  type: UITagType.success,
                  onTap: () => _showToast('成功标签被点击'),
                ),
                UITagView(
                  text: '警告标签',
                  type: UITagType.warning,
                  onTap: () => _showToast('警告标签被点击'),
                ),
                UITagView(
                  text: '错误标签',
                  type: UITagType.error,
                  onTap: () => _showToast('错误标签被点击'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildSectionTitle(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 20,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }

  void _showToast(String message) {
    // 这里可以使用 UIToast 组件显示提示
    debugPrint('Toast: $message');
  }
}

2. 高级使用

dart 复制代码
/// 自定义主题配置
class MyCustomThemeConfig implements IThemeConfig {
  const MyCustomThemeConfig();

  @override
  Color get primary => const Color(0xFF6366F1);

  @override
  Color get secondary => const Color(0xFF8B5CF6);

  @override
  Color get success => const Color(0xFF10B981);

  @override
  Color get error => const Color(0xFFEF4444);

  @override
  Color get warning => const Color(0xFFF59E0B);

  @override
  Color get info => const Color(0xFF3B82F6);

  @override
  Color get text => const Color(0xFF1F2937);

  @override
  Color get textSecondary => const Color(0xFF6B7280);

  @override
  Color get background => const Color(0xFFF9FAFB);

  @override
  Color get surface => Colors.white;

  @override
  Color get divider => const Color(0xFFE5E7EB);

  @override
  Color get border => const Color(0xFFD1D5DB);

  @override
  Color get disabled => const Color(0xFF9CA3AF);

  @override
  Color get disabledLight => const Color(0xFFF3F4F6);

  @override
  Color get tips => const Color(0xFFF59E0B);

  @override
  Color get dialogText => const Color(0xFF1F2937);

  @override
  Color get lightBlue => const Color(0xFFDBEAFE);

  @override
  Color get lighterBlue => const Color(0xFFEFF6FF);

  @override
  Color get lightGray => const Color(0xFFF3F4F6);
}

/// 应用初始化
void main() {
  // 设置自定义主题
  AppTheme.instance.setCustomConfig(const MyCustomThemeConfig());

  runApp(const MyApp());
}

/// 响应式布局示例
class ResponsiveLayout extends StatelessWidget {
  const ResponsiveLayout({super.key});

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > 1200) {
          return _buildDesktopLayout();
        } else if (constraints.maxWidth > 800) {
          return _buildTabletLayout();
        } else {
          return _buildMobileLayout();
        }
      },
    );
  }

  Widget _buildDesktopLayout() {
    return Row(
      children: [
        Expanded(
          flex: 2,
          child: _buildSidebar(),
        ),
        Expanded(
          flex: 5,
          child: _buildMainContent(),
        ),
        Expanded(
          flex: 2,
          child: _buildRightPanel(),
        ),
      ],
    );
  }

  Widget _buildTabletLayout() {
    return Column(
      children: [
        _buildHeader(),
        Expanded(
          child: Row(
            children: [
              Expanded(
                flex: 1,
                child: _buildSidebar(),
              ),
              Expanded(
                flex: 2,
                child: _buildMainContent(),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildMobileLayout() {
    return Column(
      children: [
        _buildHeader(),
        Expanded(
          child: _buildMainContent(),
        ),
        _buildBottomNavigation(),
      ],
    );
  }

  Widget _buildSidebar() {
    return UIDefaultCard(
      child: Column(
        children: [
          UIButton(
            text: '菜单项 1',
            type: UIButtonType.text,
            fullWidth: true,
            onPressed: () {},
          ),
          UIButton(
            text: '菜单项 2',
            type: UIButtonType.text,
            fullWidth: true,
            onPressed: () {},
          ),
          UIButton(
            text: '菜单项 3',
            type: UIButtonType.text,
            fullWidth: true,
            onPressed: () {},
          ),
        ],
      ),
    );
  }

  Widget _buildMainContent() {
    return UIDefaultCard(
      child: Column(
        children: [
          const Text(
            '主要内容区域',
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 16),
          UIProgressIndicator(
            value: 0.7,
            backgroundColor: Colors.grey[300]!,
            valueColor: Colors.blue,
          ),
          const SizedBox(height: 16),
          Wrap(
            spacing: 8,
            children: [
              UITagView(text: '标签 1'),
              UITagView(text: '标签 2', type: UITagType.primary),
              UITagView(text: '标签 3', type: UITagType.success),
            ],
          ),
        ],
      ),
    );
  }

  Widget _buildRightPanel() {
    return UIDefaultCard(
      child: Column(
        children: [
          const Text('右侧面板'),
          const SizedBox(height: 16),
          UIGradientCircularProgressIndicator(
            radius: 30,
            value: 0.8,
            colors: const [Colors.blue, Colors.purple],
          ),
        ],
      ),
    );
  }

  Widget _buildHeader() {
    return Container(
      padding: const EdgeInsets.all(16),
      child: Row(
        children: [
          const Text(
            '应用标题',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const Spacer(),
          UIButton(
            text: '设置',
            type: UIButtonType.outline,
            onPressed: () {},
          ),
        ],
      ),
    );
  }

  Widget _buildBottomNavigation() {
    return Container(
      padding: const EdgeInsets.all(16),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          UIButton(
            text: '首页',
            type: UIButtonType.text,
            onPressed: () {},
          ),
          UIButton(
            text: '搜索',
            type: UIButtonType.text,
            onPressed: () {},
          ),
          UIButton(
            text: '我的',
            type: UIButtonType.text,
            onPressed: () {},
          ),
        ],
      ),
    );
  }
}

📊 项目统计

代码质量指标

指标 数值 说明
总代码行数 15,000+ 包含组件、测试、示例
组件数量 50+ 覆盖常用 UI 组件
测试覆盖率 85%+ 单元测试和 Widget 测试
文档覆盖率 90%+ API 文档和使用示例
支持平台 3+ iOS、Android、Web、Desktop

性能指标

指标 数值 说明
包大小 < 500KB 压缩后的包大小
启动时间 < 100ms 组件库初始化时间
内存占用 < 10MB 运行时内存占用
渲染性能 60fps 流畅的动画和交互

🚀 总结与展望

项目亮点

  1. 完整的组件体系:覆盖了 Flutter 应用开发中的大部分 UI 需求
  2. 灵活的主题系统:支持浅色/深色主题切换,易于定制
  3. 优秀的性能表现:使用 const 构造函数和优化策略
  4. 完善的测试覆盖:确保组件的稳定性和可靠性
  5. 清晰的架构设计:模块化设计,易于维护和扩展

技术特色

  • SOLID 原则:遵循单一职责、开放封闭等设计原则
  • 响应式设计:适配不同屏幕尺寸和设备类型
  • 自定义绘制:部分组件使用 CustomPainter 实现复杂效果
  • 动画优化:使用 AnimationController 实现流畅动画
  • 状态管理:支持多种状态管理方案

未来规划

  1. 组件扩展:继续添加更多实用组件
  2. 主题丰富:提供更多预设主题方案
  3. 国际化支持:完善多语言支持
  4. 性能优化:持续优化组件性能
  5. 文档完善:提供更详细的开发文档

贡献指南

我们欢迎所有形式的贡献!如果您想参与项目开发,可以:

  1. 提交 Issue:报告 bug 或提出新功能建议
  2. 提交 PR:贡献代码或文档
  3. 分享使用经验:在社区分享使用心得
  4. 完善文档:帮助完善项目文档

Flutter UI Components 致力于为 Flutter 开发者提供一套完整、高质量、易用的 UI 组件解决方案。通过模块化的架构设计、完善的主题系统和优秀的性能表现,帮助开发者快速构建美观、流畅的 Flutter 应用。

如果您觉得这个项目对您有帮助,请给我们一个 ⭐ Star,您的支持是我们持续改进的动力!

📚 相关资源


相关推荐
想买Rolex和Supra的凯美瑞车主3 小时前
Taro + Vite 开发中 fs.allow 配置问题分析与解决
前端
ruanCat3 小时前
使用 vite 的 base 命令行参数来解决项目部署在 github page 的路径问题
前端·github
Codebee3 小时前
使用Qoder 改造前端UI/UE升级改造实践:从传统界面到现代化体验的华丽蜕变
前端·人工智能
叫我詹躲躲3 小时前
开发提速?Vue3模板隐藏技巧来了
前端·vue.js·ai编程
华仔啊3 小时前
面试都被问懵了?CSS 的 flex:1 和 flex:auto 真不是一回事!90%的人都搞错了
前端·javascript
前端康师傅3 小时前
JavaScript 函数详解
前端·javascript
金金金__3 小时前
antd v5 support React is 16 ~ 18. see https://u.ant.design/v5-for-19 for...
前端
会豪3 小时前
工业仿真(simulation)--前端(二)-资源管理器
前端
@小红花4 小时前
从0到1学习Vue框架Day03
前端·javascript·vue.js·学习·ecmascript