元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
Flutter基础
环境搭建与第一个应用
Dart语言快速入门
Flutter项目结构解析
▶
Widgets与布局
常用Widgets介绍
布局Widgets详解
自定义Widget创建
▶
状态管理
StatefulWidget与状态管理基础
Provider状态管理实战
BLoC模式入门
▶
导航与路由
页面导航基础
命名路由与参数传递
底部导航栏实现
▶
网络与数据存储
HTTP请求与Dio库使用
本地存储(SharedPreferences/SQLite)
Firebase集成指南
▶
打包与发布
Android应用打包
iOS应用打包
应用发布到商店指南
发布时间:
2025-03-22 22:17
↑
☰
# Flutter自定义Widget创建 ## 为什么需要自定义Widget? 在Flutter开发中,虽然框架提供了丰富的内置Widget,但在实际开发中我们经常需要创建自定义Widget,原因如下: - 代码复用:将常用的UI组件封装成Widget - 业务逻辑封装:将特定业务逻辑与UI绑定 - 提高可维护性:将复杂UI拆分成小的可管理单元 - 统一风格:确保应用程序UI风格的一致性 ## 创建StatelessWidget ### 基本结构 ```dart class CustomButton extends StatelessWidget { final String text; final VoidCallback onPressed; final Color? backgroundColor; const CustomButton({ super.key, required this.text, required this.onPressed, this.backgroundColor, }); @override Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: backgroundColor, padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text( text, style: TextStyle(fontSize: 16), ), ); } } // 使用自定义按钮 CustomButton( text: '确认', onPressed: () { print('按钮被点击'); }, backgroundColor: Colors.blue, ) ``` ### 组合多个Widget ```dart class ProfileCard extends StatelessWidget { final String name; final String title; final String avatarUrl; const ProfileCard({ super.key, required this.name, required this.title, required this.avatarUrl, }); @override Widget build(BuildContext context) { return Card( elevation: 4, child: Padding( padding: EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ CircleAvatar( radius: 50, backgroundImage: NetworkImage(avatarUrl), ), SizedBox(height: 16), Text( name, style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), SizedBox(height: 8), Text( title, style: TextStyle( fontSize: 16, color: Colors.grey[600], ), ), ], ), ), ); } } ``` ## 创建StatefulWidget ### 基本结构 ```dart class CounterWidget extends StatefulWidget { final int initialValue; final ValueChanged<int>? onChanged; const CounterWidget({ super.key, this.initialValue = 0, this.onChanged, }); @override State<CounterWidget> createState() => _CounterWidgetState(); } class _CounterWidgetState extends State<CounterWidget> { late int _count; @override void initState() { super.initState(); _count = widget.initialValue; } void _increment() { setState(() { _count++; widget.onChanged?.call(_count); }); } void _decrement() { setState(() { _count--; widget.onChanged?.call(_count); }); } @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: Icon(Icons.remove), onPressed: _decrement, ), Text( '$_count', style: TextStyle(fontSize: 20), ), IconButton( icon: Icon(Icons.add), onPressed: _increment, ), ], ); } } // 使用计数器组件 CounterWidget( initialValue: 5, onChanged: (value) { print('计数器值改变:$value'); }, ) ``` ### 生命周期管理 ```dart class TimerWidget extends StatefulWidget { final int duration; final VoidCallback? onFinished; const TimerWidget({ super.key, required this.duration, this.onFinished, }); @override State<TimerWidget> createState() => _TimerWidgetState(); } class _TimerWidgetState extends State<TimerWidget> { late Timer _timer; late int _remainingSeconds; @override void initState() { super.initState(); _remainingSeconds = widget.duration; _startTimer(); } void _startTimer() { _timer = Timer.periodic(Duration(seconds: 1), (timer) { setState(() { if (_remainingSeconds > 0) { _remainingSeconds--; } else { _timer.cancel(); widget.onFinished?.call(); } }); }); } @override void dispose() { _timer.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Text( '剩余时间: $_remainingSeconds 秒', style: TextStyle(fontSize: 18), ); } } ``` ## 自定义绘制 ### 使用CustomPaint ```dart class CircleProgressPainter extends CustomPainter { final double progress; final Color color; CircleProgressPainter({ required this.progress, required this.color, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = min(size.width, size.height) / 2; // 绘制背景圆 final bgPaint = Paint() ..color = Colors.grey[300]! ..style = PaintingStyle.stroke ..strokeWidth = 10.0; canvas.drawCircle(center, radius, bgPaint); // 绘制进度圆弧 final progressPaint = Paint() ..color = color ..style = PaintingStyle.stroke ..strokeWidth = 10.0 ..strokeCap = StrokeCap.round; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), -pi / 2, // 从12点钟方向开始 2 * pi * progress, // 进度对应的弧度 false, progressPaint, ); } @override bool shouldRepaint(CircleProgressPainter oldDelegate) { return oldDelegate.progress != progress || oldDelegate.color != color; } } class CircleProgressBar extends StatelessWidget { final double progress; final Color color; final double size; const CircleProgressBar({ super.key, required this.progress, this.color = Colors.blue, this.size = 100, }) : assert(progress >= 0 && progress <= 1); @override Widget build(BuildContext context) { return CustomPaint( size: Size(size, size), painter: CircleProgressPainter( progress: progress, color: color, ), ); } } ``` ## 最佳实践 ### 1. 参数验证 ```dart class RatingBar extends StatelessWidget { final int value; final int maxStars; final double starSize; final ValueChanged<int>? onChanged; const RatingBar({ super.key, required this.value, this.maxStars = 5, this.starSize = 24, this.onChanged, }) : assert(value >= 0 && value <= maxStars, 'Rating value must be between 0 and maxStars'); @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: List.generate(maxStars, (index) { return IconButton( icon: Icon( index < value ? Icons.star : Icons.star_border, size: starSize, color: Colors.amber, ), onPressed: onChanged == null ? null : () { onChanged?.call(index + 1); }, ); }), ); } } ``` ### 2. 主题适配 ```dart class ThemedCard extends StatelessWidget { final String title; final String content; const ThemedCard({ super.key, required this.title, required this.content, }); @override Widget build(BuildContext context) { final theme = Theme.of(context); return Card( elevation: 2, child: Padding( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: theme.textTheme.titleLarge, ), SizedBox(height: 8), Text( content, style: theme.textTheme.bodyMedium, ), ], ), ), ); } } ``` ### 3. 响应式设计 ```dart class ResponsiveContainer extends StatelessWidget { final Widget child; final double maxWidth; const ResponsiveContainer({ super.key, required this.child, this.maxWidth = 600, }); @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final width = min(constraints.maxWidth, maxWidth); return Center( child: SizedBox( width: width, child: child, ), ); }, ); } } ``` ### 4. 错误处理 ```dart class ImageWithFallback extends StatelessWidget { final String imageUrl; final double width; final double height; const ImageWithFallback({ super.key, required this.imageUrl, required this.width, required this.height, }); @override Widget build(BuildContext context) { return Image.network( imageUrl, width: width, height: height, fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( width: width, height: height, color: Colors.grey[200], child: Icon( Icons.error_outline, color: Colors.red, ), ); }, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Container( width: width, height: height, color: Colors.grey[200], child: Center( child: CircularProgressIndicator( value: loadingProgress.expectedTotalBytes != null ? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes! : null, ), ), ); }, ); } } ``` ## 总结 本文详细介绍了Flutter中自定义Widget的创建方法,包括: 1. StatelessWidget的创建和使用 2. StatefulWidget的实现和生命周期管理 3. 自定义绘制的实现 4. 最佳实践和注意事项 建议: - 合理划分Widget的职责 - 保持Widget的可复用性 - 注意性能优化 - 做好参数验证和错误处理 - 遵循Flutter的设计规范