一、什么是Widget?理解Flutter的构建理念
1.1 Widget的核心思想
在Flutter中,一切皆Widget。这种设计理念让Flutter的UI构建既灵活又强大:
dart
复制
下载
// Widget就像乐高积木
// 小积木 → 大积木 → 完整模型
Text('Hello') → Row([Text, Icon]) → Scaffold(整个页面)
1.2 Widget vs Element vs RenderObject
理解这三个核心概念的关系:
dart
复制
下载
// 三棵树架构
Widget树 (配置) → Element树 (实例) → RenderObject树 (渲染)
↑ ↑ ↑
配置信息 管理生命周期 实际绘制到屏幕
生动比喻:
-
Widget = 建筑蓝图(描述如何建造)
-
Element = 建筑工地(管理建造过程)
-
RenderObject = 实际建筑物(最终成品)
二、StatelessWidget深度解析
2.1 什么是StatelessWidget?
不可变Widget,一旦创建就不能改变。适用于静态内容。
dart
复制
下载
class GreetingWidget extends StatelessWidget {
final String name;
final Color textColor;
// const构造函数 - 性能优化关键
const GreetingWidget({
super.key,
required this.name,
this.textColor = Colors.black,
});
@override
Widget build(BuildContext context) {
// build方法每次都会被调用
return Text(
'你好,$name!',
style: TextStyle(
color: textColor,
fontSize: 20,
fontWeight: FontWeight.bold,
),
);
}
}
// 使用示例
void statelessDemo() {
return const Scaffold(
body: Center(
child: GreetingWidget(
name: '小明',
textColor: Colors.blue,
),
),
);
}
2.2 StatelessWidget的最佳实践
dart
复制
下载
// 1. 始终使用const构造函数(如果可能)
const MyWidget();
// 2. 将Widget拆分为小的、可复用的组件
class UserProfile extends StatelessWidget {
final User user;
const UserProfile({super.key, required this.user});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 拆分为更小的Widget
_buildAvatar(),
_buildUserName(),
_buildUserStats(),
],
);
}
Widget _buildAvatar() {
return CircleAvatar(
backgroundImage: NetworkImage(user.avatarUrl),
radius: 40,
);
}
Widget _buildUserName() {
return Text(
user.name,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
);
}
Widget _buildUserStats() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_buildStatItem('关注', user.followingCount),
_buildStatItem('粉丝', user.followerCount),
_buildStatItem('帖子', user.postCount),
],
);
}
Widget _buildStatItem(String label, int count) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
Text(
'$count',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
Text(
label,
style: TextStyle(color: Colors.grey[600]),
),
],
),
);
}
}
2.3 何时使用StatelessWidget?
-
展示静态数据
-
不需要用户交互
-
依赖外部传入的数据
-
纯展示型组件(按钮、图标、文本等)
三、StatefulWidget深度解析
3.1 什么是StatefulWidget?
可变Widget,可以管理自己的状态变化。
dart
复制
下载
class CounterWidget extends StatefulWidget {
final String title;
const CounterWidget({super.key, required this.title});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
// 状态变量
int _counter = 0;
bool _isFavorite = false;
// 状态更新方法
void _incrementCounter() {
setState(() {
// 在这里修改状态
_counter++;
});
// setState会触发build方法重新调用
}
void _toggleFavorite() {
setState(() {
_isFavorite = !_isFavorite;
});
}
@override
Widget build(BuildContext context) {
// 每次状态变化都会重新构建
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
widget.title, // 访问widget属性
style: const TextStyle(fontSize: 24),
),
const SizedBox(height: 20),
Text(
'计数: $_counter',
style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: _incrementCounter,
icon: const Icon(Icons.add),
iconSize: 40,
),
IconButton(
onPressed: _toggleFavorite,
icon: Icon(
_isFavorite ? Icons.favorite : Icons.favorite_border,
color: _isFavorite ? Colors.red : Colors.grey,
),
iconSize: 40,
),
],
),
// 根据状态显示不同内容
if (_counter > 10)
const Text(
'计数器已经很大了!',
style: TextStyle(color: Colors.orange),
),
],
);
}
}
3.2 StatefulWidget的生命周期
dart
复制
下载
class LifecycleDemo extends StatefulWidget {
const LifecycleDemo({super.key});
@override
State<LifecycleDemo> createState() => _LifecycleDemoState();
}
class _LifecycleDemoState extends State<LifecycleDemo>
with WidgetsBindingObserver {
int _counter = 0;
String _status = '初始化';
@override
void initState() {
super.initState();
_status = 'initState: Widget创建';
print(_status);
// 添加应用状态观察者
WidgetsBinding.instance.addObserver(this);
// 模拟数据初始化
Future.delayed(const Duration(seconds: 1), () {
if (mounted) {
setState(() {
_counter = 100;
_status = '数据加载完成';
});
}
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print('didChangeDependencies: 依赖变化');
// InheritedWidget变化时调用
}
@override
void didUpdateWidget(LifecycleDemo oldWidget) {
super.didUpdateWidget(oldWidget);
print('didUpdateWidget: Widget更新');
// 父Widget重建并传入新配置时调用
}
@override
void setState(VoidCallback fn) {
print('setState: 准备更新状态');
super.setState(fn);
}
@override
void deactivate() {
print('deactivate: Widget从树中移除');
super.deactivate();
}
@override
void dispose() {
print('dispose: Widget永久销毁');
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
// WidgetsBindingObserver方法
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print('应用状态变化: $state');
}
@override
void didChangeMetrics() {
print('屏幕尺寸变化');
}
@override
void didChangeAccessibilityFeatures() {
print('无障碍功能变化');
}
@override
Widget build(BuildContext context) {
print('build: 构建界面');
return Scaffold(
appBar: AppBar(title: const Text('生命周期演示')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('状态: $_status', style: const TextStyle(fontSize: 20)),
const SizedBox(height: 20),
Text('计数器: $_counter', style: const TextStyle(fontSize: 48)),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
setState(() {
_counter++;
_status = '用户点击增加';
});
},
child: const Text('增加'),
),
],
),
),
);
}
}
3.3 状态管理的几种模式
dart
复制
下载
// 模式1:Widget自身管理状态(适合局部状态)
class SelfManagedCounter extends StatefulWidget {
const SelfManagedCounter({super.key});
@override
State<SelfManagedCounter> createState() => _SelfManagedCounterState();
}
// 模式2:父Widget管理状态(适合共享状态)
class ParentManagedCounter extends StatelessWidget {
final int counter;
final VoidCallback onIncrement;
const ParentManagedCounter({
super.key,
required this.counter,
required this.onIncrement,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('计数器: $counter'),
ElevatedButton(
onPressed: onIncrement,
child: const Text('增加'),
),
],
);
}
}
// 模式3:混合模式
class ProductCard extends StatefulWidget {
final Product product;
final Function(Product) onAddToCart;
const ProductCard({
super.key,
required this.product,
required this.onAddToCart,
});
@override
State<ProductCard> createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard> {
// 本地状态:是否被点击
bool _isTapped = false;
// 本地状态:动画控制器
late AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
void _handleTap() {
setState(() {
_isTapped = true;
});
_animationController.forward().then((_) {
widget.onAddToCart(widget.product);
setState(() {
_isTapped = false;
});
_animationController.reset();
});
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _handleTap,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _isTapped ? Colors.blue[50] : Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: _isTapped ? Colors.blue : Colors.grey[300]!,
),
boxShadow: _isTapped
? [BoxShadow(color: Colors.blue.withOpacity(0.2), blurRadius: 10)]
: [BoxShadow(color: Colors.grey.withOpacity(0.1), blurRadius: 4)],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(widget.product.imageUrl, height: 120),
const SizedBox(height: 8),
Text(widget.product.name, style: const TextStyle(fontSize: 16)),
Text('¥${widget.product.price}',
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Icon(
_isTapped ? Icons.check_circle : Icons.add_shopping_cart,
color: _isTapped ? Colors.green : Colors.blue,
),
],
),
),
);
}
}
四、常用基础Widget详解
4.1 文本与图标
dart
复制
下载
class TextAndIconDemo extends StatelessWidget {
const TextAndIconDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 1. 基础Text
const Text(
'基础文本',
style: TextStyle(fontSize: 24),
),
// 2. 富文本
const Text.rich(
TextSpan(
text: 'Hello ',
style: TextStyle(color: Colors.black),
children: [
TextSpan(
text: 'Flutter',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
TextSpan(
text: ' World!',
style: TextStyle(
color: Colors.green,
fontStyle: FontStyle.italic,
),
),
],
),
),
// 3. 最大行数和溢出
const Text(
'这是一个非常长的文本,当它超过最大行数时会显示省略号...',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 20),
// 4. 图标
const Row(
children: [
Icon(Icons.star, color: Colors.amber),
Icon(Icons.favorite, color: Colors.red),
Icon(Icons.thumb_up, color: Colors.blue),
Icon(Icons.share, color: Colors.green),
],
),
// 5. 图标按钮
IconButton(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('图标被点击')),
);
},
icon: const Icon(Icons.settings),
iconSize: 40,
color: Colors.purple,
),
// 6. 自定义字体
const Text(
'自定义字体',
style: TextStyle(
fontFamily: 'Roboto',
fontSize: 24,
fontWeight: FontWeight.w300,
),
),
],
),
),
);
}
}
4.2 容器与装饰
dart
复制
下载
class ContainerDemo extends StatelessWidget {
const ContainerDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: SingleChildScrollView(
child: Column(
children: [
// 1. 基础Container
Container(
width: 200,
height: 100,
color: Colors.blue,
child: const Center(
child: Text(
'基础容器',
style: TextStyle(color: Colors.white),
),
),
),
const SizedBox(height: 20),
// 2. 带装饰的Container
Container(
width: 200,
height: 100,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 2,
blurRadius: 7,
offset: const Offset(0, 3),
),
],
gradient: const LinearGradient(
colors: [Colors.pink, Colors.purple],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
border: Border.all(
color: Colors.deepPurple,
width: 2,
),
),
child: const Center(
child: Text(
'装饰容器',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 20),
// 3. 圆形头像
Container(
width: 100,
height: 100,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[300],
image: const DecorationImage(
image: NetworkImage('https://picsum.photos/200'),
fit: BoxFit.cover,
),
border: Border.all(
color: Colors.blue,
width: 3,
),
),
),
const SizedBox(height: 20),
// 4. 带内边距和内容的Container
Container(
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.orange[50],
borderRadius: BorderRadius.circular(15),
),
child: Column(
children: [
const Text(
'卡片标题',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
const Text('这是一个带内边距和外边距的容器'),
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('项目1'),
Icon(Icons.arrow_forward_ios, size: 16),
],
),
),
],
),
),
],
),
),
),
);
}
}
4.3 布局Widget
dart
复制
下载
class LayoutDemo extends StatelessWidget {
const LayoutDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('布局演示')),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 1. Column - 垂直排列
const Text('Column 垂直布局:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildColoredBox(Colors.red, 'Item 1'),
_buildColoredBox(Colors.green, 'Item 2'),
_buildColoredBox(Colors.blue, 'Item 3'),
],
),
),
// 2. Row - 水平排列
const Text('Row 水平布局:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildColoredBox(Colors.red, 'Left'),
_buildColoredBox(Colors.green, 'Center'),
_buildColoredBox(Colors.blue, 'Right'),
],
),
),
// 3. Stack - 层叠布局
const Text('Stack 层叠布局:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Container(
height: 200,
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Stack(
children: [
// 底层
Container(
color: Colors.blue[100],
),
// 中层
Positioned(
top: 20,
left: 20,
child: Container(
width: 100,
height: 100,
color: Colors.red.withOpacity(0.7),
child: const Center(child: Text('层1')),
),
),
// 上层
Positioned(
top: 50,
left: 50,
child: Container(
width: 100,
height: 100,
color: Colors.green.withOpacity(0.7),
child: const Center(child: Text('层2')),
),
),
// 文字层
const Positioned(
bottom: 10,
right: 10,
child: Text('Stack示例'),
),
],
),
),
// 4. Expanded - 弹性布局
const Text('Expanded 弹性布局:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Container(
height: 80,
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.red,
child: const Center(child: Text('1份')),
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.green,
child: const Center(child: Text('2份')),
),
),
Expanded(
flex: 3,
child: Container(
color: Colors.blue,
child: const Center(child: Text('3份')),
),
),
],
),
),
// 5. Wrap - 流式布局
const Text('Wrap 流式布局:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(bottom: 20),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Wrap(
spacing: 8, // 水平间距
runSpacing: 8, // 垂直间距
children: [
_buildChip('Flutter'),
_buildChip('Dart'),
_buildChip('Widget'),
_buildChip('Stateful'),
_buildChip('Stateless'),
_buildChip('Material Design'),
_buildChip('Cupertino'),
_buildChip('Hot Reload'),
_buildChip('Cross Platform'),
],
),
),
],
),
),
),
);
}
Widget _buildColoredBox(Color color, String text) {
return Container(
width: 80,
height: 60,
color: color,
child: Center(
child: Text(
text,
style: const TextStyle(color: Colors.white),
),
),
);
}
Widget _buildChip(String label) {
return Chip(
label: Text(label),
avatar: CircleAvatar(
backgroundColor: Colors.blue[100],
child: Text(label[0]),
),
backgroundColor: Colors.blue[50],
);
}
}
五、Widget性能优化技巧
5.1 const构造函数的使用
dart
复制
下载
class PerformanceDemo extends StatelessWidget {
const PerformanceDemo({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// ❌ 错误示例:每次重建都会创建新对象
Text('Hello'),
Container(color: Colors.red),
Icon(Icons.star),
// ✅ 正确示例:使用const
const Text('Hello'),
const Container(color: Colors.red),
const Icon(Icons.star),
// 甚至整个子树都可以是const
const Column(
children: [
Text('标题'),
SizedBox(height: 10),
Text('副标题'),
],
),
],
);
}
}
5.2 避免不必要的重建
dart
复制
下载
class OptimizedWidget extends StatefulWidget {
const OptimizedWidget({super.key});
@override
State<OptimizedWidget> createState() => _OptimizedWidgetState();
}
class _OptimizedWidgetState extends State<OptimizedWidget> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
// ❌ 错误:每次重建都会创建新的回调函数
// ElevatedButton(
// onPressed: () => setState(() => _counter++),
// child: Text('增加: $_counter'),
// ),
// ✅ 正确:缓存回调函数
ElevatedButton(
onPressed: _incrementCounter,
child: Text('增加: $_counter'),
),
// 使用const构造函数的部分
const SizedBox(height: 20),
const Text('静态文本,不会变化'),
const Icon(Icons.info),
// 使用Builder避免不必要的重建
Builder(
builder: (context) {
// 这部分只会在需要时重建
return Text('动态内容: $_counter');
},
),
],
);
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
}
5.3 使用Key优化列表性能
dart
复制
下载
class TodoList extends StatefulWidget {
const TodoList({super.key});
@override
State<TodoList> createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
final List<TodoItem> _items = [
TodoItem(id: '1', text: '学习Flutter'),
TodoItem(id: '2', text: '写博客'),
TodoItem(id: '3', text: '做练习'),
];
void _addItem() {
setState(() {
_items.insert(0, TodoItem(
id: DateTime.now().toString(),
text: '新任务 ${_items.length + 1}',
));
});
}
void _removeItem(int index) {
setState(() {
_items.removeAt(index);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: _items.length,
// 使用Key优化列表项性能
itemBuilder: (context, index) {
final item = _items[index];
return Dismissible(
// Key确保Flutter能正确识别每个项
key: ValueKey(item.id),
onDismissed: (direction) => _removeItem(index),
background: Container(color: Colors.red),
child: ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text(item.text),
subtitle: Text('ID: ${item.id}'),
trailing: IconButton(
icon: const Icon(Icons.delete),
onPressed: () => _removeItem(index),
),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _addItem,
child: const Icon(Icons.add),
),
);
}
}
class TodoItem {
final String id;
final String text;
TodoItem({required this.id, required this.text});
}
六、实战练习:创建一个完整的微博卡片
dart
复制
下载
class WeiboCard extends StatefulWidget {
final WeiboPost post;
const WeiboCard({super.key, required this.post});
@override
State<WeiboCard> createState() => _WeiboCardState();
}
class _WeiboCardState extends State<WeiboCard> {
bool _isLiked = false;
int _likeCount = 0;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_likeCount = widget.post.likeCount;
_isLiked = widget.post.isLiked;
}
void _toggleLike() {
setState(() {
if (_isLiked) {
_likeCount--;
} else {
_likeCount++;
}
_isLiked = !_isLiked;
});
}
void _toggleExpand() {
setState(() {
_isExpanded = !_isExpanded;
});
}
void _showCommentSheet() {
showModalBottomSheet(
context: context,
builder: (context) => CommentSheet(postId: widget.post.id),
);
}
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 用户信息行
Row(
children: [
CircleAvatar(
backgroundImage: NetworkImage(widget.post.userAvatar),
radius: 20,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.post.userName,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
Text(
widget.post.postTime,
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
],
),
),
IconButton(
icon: const Icon(Icons.more_vert),
onPressed: () {},
),
],
),
const SizedBox(height: 12),
// 微博内容
GestureDetector(
onTap: _toggleExpand,
child: Text(
widget.post.content,
maxLines: _isExpanded ? null : 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 15),
),
),
// 查看更多按钮
if (widget.post.content.length > 100 && !_isExpanded)
TextButton(
onPressed: _toggleExpand,
child: const Text('展开全文'),
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
),
),
// 图片展示
if (widget.post.images.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 12),
child: GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
),
itemCount: widget.post.images.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
// 查看大图
},
child: Image.network(
widget.post.images[index],
fit: BoxFit.cover,
),
);
},
),
),
// 统计信息
Padding(
padding: const EdgeInsets.only(top: 12),
child: Row(
children: [
Text(
'转发 ${widget.post.repostCount}',
style: TextStyle(color: Colors.grey[600]),
),
const SizedBox(width: 16),
Text(
'评论 ${widget.post.commentCount}',
style: TextStyle(color: Colors.grey[600]),
),
const SizedBox(width: 16),
Text(
'点赞 $_likeCount',
style: TextStyle(color: Colors.grey[600]),
),
],
),
),
// 操作按钮
const Divider(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildActionButton(
icon: Icons.repeat,
label: '转发',
onTap: () {},
),
_buildActionButton(
icon: Icons.comment,
label: '评论',
onTap: _showCommentSheet,
),
_buildActionButton(
icon: _isLiked ? Icons.favorite : Icons.favorite_border,
label: '点赞',
color: _isLiked ? Colors.red : Colors.grey,
onTap: _toggleLike,
),
_buildActionButton(
icon: Icons.share,
label: '分享',
onTap: () {},
),
],
),
],
),
),
);
}
Widget _buildActionButton({
required IconData icon,
required String label,
required VoidCallback onTap,
Color? color,
}) {
return InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(20),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
children: [
Icon(icon, color: color ?? Colors.grey[600], size: 20),
const SizedBox(width: 4),
Text(label, style: TextStyle(color: Colors.grey[600])),
],
),
),
);
}
}
// 数据模型
class WeiboPost {
final String id;
final String userName;
final String userAvatar;
final String postTime;
final String content;
final List<String> images;
final int repostCount;
final int commentCount;
final int likeCount;
final bool isLiked;
WeiboPost({
required this.id,
required this.userName,
required this.userAvatar,
required this.postTime,
required this.content,
required this.images,
required this.repostCount,
required this.commentCount,
required this.likeCount,
required this.isLiked,
});
}