
文章目录
-
-
- [2.1 ListView - 就像滚动的清单](#2.1 ListView - 就像滚动的清单)
- [2.2 GridView - 就像网格展示](#2.2 GridView - 就像网格展示)
- [2.3 Stack - 就像叠放的卡片](#2.3 Stack - 就像叠放的卡片)
- [2.4 Wrap - 就像自动换行的文字](#2.4 Wrap - 就像自动换行的文字)
- [🎯 实践练习:创建一个完整的应用界面](#🎯 实践练习:创建一个完整的应用界面)
- [📚 学习总结](#📚 学习总结)
-
- [🧱 常用布局Widget](#🧱 常用布局Widget)
- [🎨 实践能力](#🎨 实践能力)
- [🚀 下一步](#🚀 下一步)
-
2.1 ListView - 就像滚动的清单
ListView就像一个可以滚动的清单,比如购物清单、联系人列表、新闻列表等。

dart
class ListViewExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('列表展示大全')),
body: DefaultTabController(
length: 4,
child: Column(
children: [
TabBar(
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: [
Tab(text: '基础列表'),
Tab(text: '分隔线'),
Tab(text: '构建器'),
Tab(text: '自定义'),
],
),
Expanded(
child: TabBarView(
children: [
_buildBasicListView(),
_buildSeparatedListView(),
_buildBuilderListView(),
_buildCustomListView(),
],
),
),
],
),
),
);
}
// 基础列表 - 就像简单的购物清单
Widget _buildBasicListView() {
return ListView(
padding: EdgeInsets.all(16),
children: [
ListTile(
leading: Icon(Icons.shopping_cart),
title: Text('苹果'),
subtitle: Text('新鲜水果'),
trailing: Text('¥5.00'),
),
ListTile(
leading: Icon(Icons.shopping_cart),
title: Text('香蕉'),
subtitle: Text('进口水果'),
trailing: Text('¥3.00'),
),
ListTile(
leading: Icon(Icons.shopping_cart),
title: Text('橙子'),
subtitle: Text('维C丰富'),
trailing: Text('¥4.00'),
),
// 也可以放其他Widget
Container(
height: 100,
margin: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.blue[100],
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Text('这是一个自定义容器'),
),
),
],
);
}
// 带分隔线的列表 - 就像有分割线的笔记本
Widget _buildSeparatedListView() {
List<String> items = List.generate(20, (index) => '项目 ${index + 1}');
return ListView.separated(
padding: EdgeInsets.all(16),
itemCount: items.length,
separatorBuilder: (context, index) => Divider(), // 分隔线
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: Text('${index + 1}'),
),
title: Text(items[index]),
subtitle: Text('这是第${index + 1}个项目的描述'),
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('点击了${items[index]}')),
);
},
);
},
);
}
// 构建器列表 - 就像按需制作的清单
Widget _buildBuilderListView() {
return ListView.builder(
padding: EdgeInsets.all(16),
itemCount: 1000, // 可以是很大的数字
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(
index % 2 == 0 ? Icons.star : Icons.favorite,
color: index % 2 == 0 ? Colors.orange : Colors.red,
),
title: Text('动态项目 $index'),
subtitle: Text('这是第$index个动态生成的项目'),
trailing: IconButton(
icon: Icon(Icons.more_vert),
onPressed: () {
_showItemMenu(context, index);
},
),
),
);
},
);
}
// 自定义列表项 - 就像精心设计的名片
Widget _buildCustomListView() {
List<Map<String, dynamic>> contacts = [
{'name': '张三', 'phone': '138****1234', 'avatar': Icons.person, 'color': Colors.blue},
{'name': '李四', 'phone': '139****5678', 'avatar': Icons.person_outline, 'color': Colors.green},
{'name': '王五', 'phone': '137****9012', 'avatar': Icons.account_circle, 'color': Colors.orange},
{'name': '赵六', 'phone': '136****3456', 'avatar': Icons.face, 'color': Colors.purple},
];
return ListView.builder(
padding: EdgeInsets.all(16),
itemCount: contacts.length,
itemBuilder: (context, index) {
final contact = contacts[index];
return Container(
margin: EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: ListTile(
contentPadding: EdgeInsets.all(16),
leading: CircleAvatar(
backgroundColor: contact['color'],
child: Icon(contact['avatar'], color: Colors.white),
),
title: Text(
contact['name'],
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 4),
Text(contact['phone']),
SizedBox(height: 4),
Text(
'在线',
style: TextStyle(color: Colors.green, fontSize: 12),
),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: Icon(Icons.call, color: Colors.green),
onPressed: () => _makeCall(contact['name']),
),
IconButton(
icon: Icon(Icons.message, color: Colors.blue),
onPressed: () => _sendMessage(contact['name']),
),
],
),
),
);
},
);
}
void _showItemMenu(BuildContext context, int index) {
showModalBottomSheet(
context: context,
builder: (context) => Container(
padding: EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.edit),
title: Text('编辑'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: Icon(Icons.delete),
title: Text('删除'),
onTap: () => Navigator.pop(context),
),
],
),
),
);
}
void _makeCall(String name) {
print('拨打电话给 $name');
}
void _sendMessage(String name) {
print('发送消息给 $name');
}
}
2.2 GridView - 就像网格展示
GridView就像商品展示柜、相册、应用图标网格等。

dart
class GridViewExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('网格展示大全')),
body: DefaultTabController(
length: 3,
child: Column(
children: [
TabBar(
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
tabs: [
Tab(text: '固定列数'),
Tab(text: '固定大小'),
Tab(text: '瀑布流'),
],
),
Expanded(
child: TabBarView(
children: [
_buildCountGridView(),
_buildExtentGridView(),
_buildStaggeredGridView(),
],
),
),
],
),
),
);
}
// 固定列数网格 - 就像整齐的商品陈列
Widget _buildCountGridView() {
return GridView.count(
padding: EdgeInsets.all(16),
crossAxisCount: 2, // 每行2个
crossAxisSpacing: 10, // 水平间距
mainAxisSpacing: 10, // 垂直间距
childAspectRatio: 0.8, // 宽高比
children: List.generate(20, (index) {
return Container(
decoration: BoxDecoration(
color: Colors.primaries[index % Colors.primaries.length],
borderRadius: BorderRadius.circular(12),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.shopping_bag,
size: 40,
color: Colors.white,
),
SizedBox(height: 8),
Text(
'商品 ${index + 1}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
Text(
'¥${(index + 1) * 10}',
style: TextStyle(
color: Colors.white70,
),
),
],
),
);
}),
);
}
// 固定大小网格 - 就像固定尺寸的相框
Widget _buildExtentGridView() {
return GridView.extent(
padding: EdgeInsets.all(16),
maxCrossAxisExtent: 150, // 最大宽度150
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: List.generate(30, (index) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.blue[300]!,
Colors.blue[600]!,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.photo, size: 30, color: Colors.white),
SizedBox(height: 4),
Text(
'照片 $index',
style: TextStyle(color: Colors.white),
),
],
),
),
);
}),
);
}
// 瀑布流网格 - 就像Pinterest的布局
Widget _buildStaggeredGridView() {
return GridView.builder(
padding: EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: 0.7,
),
itemCount: 20,
itemBuilder: (context, index) {
// 随机高度,模拟瀑布流效果
double height = 150 + (index % 3) * 50.0;
return Container(
height: height,
decoration: BoxDecoration(
color: Colors.primaries[index % Colors.primaries.length].withOpacity(0.3),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.primaries[index % Colors.primaries.length],
width: 2,
),
),
child: Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(
Icons.image,
size: 30,
color: Colors.primaries[index % Colors.primaries.length],
),
SizedBox(height: 8),
Text(
'卡片 ${index + 1}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 4),
Text(
'这是第${index + 1}个卡片的描述内容,高度会根据内容自动调整。',
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
Spacer(),
Row(
children: [
Icon(Icons.favorite_border, size: 16),
SizedBox(width: 4),
Text('${index + 1}'),
Spacer(),
Icon(Icons.share, size: 16),
],
),
],
),
),
);
},
);
}
}
2.3 Stack - 就像叠放的卡片
Stack就像把多张卡片叠在一起,可以创建层叠效果。

dart
class StackExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('层叠布局演示')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
// 基础层叠 - 就像叠放的照片
Text('基础层叠:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
height: 200,
child: Stack(
children: [
// 底层 - 背景
Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue[300]!, Colors.blue[600]!],
),
borderRadius: BorderRadius.circular(12),
),
),
// 中层 - 装饰
Positioned(
top: 20,
right: 20,
child: Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
shape: BoxShape.circle,
),
),
),
// 顶层 - 内容
Positioned(
bottom: 20,
left: 20,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'层叠标题',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
Text(
'这是层叠在背景上的文字',
style: TextStyle(color: Colors.white70),
),
],
),
),
],
),
),
SizedBox(height: 32),
// 用户头像卡片 - 实际应用示例
Text('用户头像卡片:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
height: 180,
child: Stack(
children: [
// 背景卡片
Container(
margin: EdgeInsets.only(top: 40),
padding: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 8,
offset: Offset(0, 4),
),
],
),
child: Column(
children: [
Text(
'张三',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 4),
Text(
'Flutter开发工程师',
style: TextStyle(
color: Colors.grey[600],
fontSize: 14,
),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildStatItem('项目', '12'),
_buildStatItem('经验', '3年'),
_buildStatItem('评分', '4.8'),
],
),
],
),
),
// 头像(浮在卡片上方)
Positioned(
top: 0,
left: 0,
right: 0,
child: Center(
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 4),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 8,
),
],
),
child: CircleAvatar(
radius: 36,
backgroundColor: Colors.blue,
child: Icon(Icons.person, size: 40, color: Colors.white),
),
),
),
),
// 在线状态指示器
Positioned(
top: 50,
left: 0,
right: -30,
child: Center(
child: Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
border: Border.all(color: Colors.white, width: 2),
),
),
),
),
],
),
),
SizedBox(height: 32),
// 商品卡片 - 带标签的示例
Text('商品卡片:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
height: 200,
child: Stack(
children: [
// 主卡片
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 商品图片区域
Container(
height: 120,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
),
child: Center(
child: Icon(Icons.image, size: 50, color: Colors.grey),
),
),
// 商品信息
Padding(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'iPhone 15 Pro',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 4),
Text(
'¥8999',
style: TextStyle(
color: Colors.red,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
// 折扣标签
Positioned(
top: 8,
left: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'8折',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
),
// 收藏按钮
Positioned(
top: 8,
right: 8,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
shape: BoxShape.circle,
),
child: Icon(
Icons.favorite_border,
size: 20,
color: Colors.grey[600],
),
),
),
// 新品标签
Positioned(
top: 50,
left: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.orange,
borderRadius: BorderRadius.circular(3),
),
child: Text(
'NEW',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
],
),
),
);
}
Widget _buildStatItem(String label, String value) {
return Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
Text(
label,
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
);
}
}
2.4 Wrap - 就像自动换行的文字
Wrap就像写文章时的自动换行,当一行放不下时会自动换到下一行。

dart
class WrapExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('自动换行布局')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标签云 - 就像文章的标签
Text('标签云:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 8, // 水平间距
runSpacing: 8, // 垂直间距
children: [
'Flutter', 'Dart', 'Mobile', 'iOS', 'Android',
'Web', 'Desktop', 'UI', 'UX', 'Design',
'Development', 'Programming', 'Code', 'App'
].map((tag) => Chip(
label: Text(tag),
backgroundColor: Colors.blue[100],
labelStyle: TextStyle(color: Colors.blue[800]),
)).toList(),
),
SizedBox(height: 32),
// 颜色选择器 - 就像调色板
Text('颜色选择器:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 12,
runSpacing: 12,
children: Colors.primaries.map((color) => GestureDetector(
onTap: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('选择了颜色: ${color.toString()}')),
);
},
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
border: Border.all(color: Colors.grey[300]!, width: 2),
),
),
)).toList(),
),
SizedBox(height: 32),
// 尺寸选择 - 就像服装尺码
Text('尺寸选择:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: ['XS', 'S', 'M', 'L', 'XL', 'XXL'].map((size) =>
Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(20),
),
child: Text(size),
)
).toList(),
),
SizedBox(height: 32),
// 功能按钮组 - 就像工具栏
Text('功能按钮组:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
{'icon': Icons.copy, 'label': '复制'},
{'icon': Icons.cut, 'label': '剪切'},
{'icon': Icons.paste, 'label': '粘贴'},
{'icon': Icons.undo, 'label': '撤销'},
{'icon': Icons.redo, 'label': '重做'},
{'icon': Icons.save, 'label': '保存'},
{'icon': Icons.print, 'label': '打印'},
{'icon': Icons.share, 'label': '分享'},
].map((item) => ElevatedButton.icon(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('点击了${item['label']}')),
);
},
icon: Icon(item['icon'] as IconData, size: 16),
label: Text(item['label'] as String),
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
),
)).toList(),
),
SizedBox(height: 32),
// 联系人头像 - 就像群聊头像
Text('联系人头像:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Wrap(
spacing: 8,
runSpacing: 8,
children: List.generate(15, (index) => CircleAvatar(
radius: 25,
backgroundColor: Colors.primaries[index % Colors.primaries.length],
child: Text(
String.fromCharCode(65 + index), // A, B, C...
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
)),
),
SizedBox(height: 32),
// 自定义间距的Wrap
Text('自定义间距:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
SizedBox(height: 16),
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(8),
),
child: Wrap(
spacing: 20, // 更大的水平间距
runSpacing: 15, // 更大的垂直间距
alignment: WrapAlignment.center, // 居中对齐
children: [
'居中', '对齐', '的', '标签', '会', '自动', '换行', '并且', '保持', '居中'
].map((text) => Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.blue[200],
borderRadius: BorderRadius.circular(15),
),
child: Text(text),
)).toList(),
),
),
],
),
),
);
}
}
🎯 实践练习:创建一个完整的应用界面
让我们综合运用所学的布局知识,创建一个仿微信朋友圈的界面:

dart
class SocialMediaApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '社交媒体',
theme: ThemeData(primarySwatch: Colors.blue),
home: SocialMediaHome(),
);
}
}
class SocialMediaHome extends StatelessWidget {
final List<Map<String, dynamic>> posts = [
{
'user': '张三',
'avatar': Icons.person,
'time': '2小时前',
'content': '今天天气真不错,出来散散步,心情都变好了! 🌞',
'images': 3,
'likes': 15,
'comments': 3,
},
{
'user': '李四',
'avatar': Icons.face,
'time': '4小时前',
'content': '刚刚完成了一个Flutter项目,感觉Flutter真的很棒!分享一些开发心得...',
'images': 1,
'likes': 28,
'comments': 7,
},
{
'user': '王五',
'avatar': Icons.account_circle,
'time': '6小时前',
'content': '周末和朋友们一起去爬山,虽然累但是很开心!',
'images': 4,
'likes': 42,
'comments': 12,
},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('朋友圈'),
backgroundColor: Colors.green[600],
actions: [
IconButton(
icon: Icon(Icons.camera_alt),
onPressed: () {},
),
],
),
body: ListView.builder(
itemCount: posts.length,
itemBuilder: (context, index) {
return _buildPostCard(context, posts[index]);
},
),
);
}
Widget _buildPostCard(BuildContext context, Map<String, dynamic> post) {
return Container(
margin: EdgeInsets.symmetric(vertical: 4),
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(color: Colors.grey[200]!, width: 1),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 用户信息行
Row(
children: [
// 头像
CircleAvatar(
radius: 25,
backgroundColor: Colors.blue,
child: Icon(post['avatar'], color: Colors.white),
),
SizedBox(width: 12),
// 用户名和时间
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
post['user'],
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 2),
Text(
post['time'],
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
],
),
),
// 更多按钮
IconButton(
icon: Icon(Icons.more_horiz, color: Colors.grey),
onPressed: () {},
),
],
),
SizedBox(height: 12),
// 文字内容
Text(
post['content'],
style: TextStyle(fontSize: 15, height: 1.4),
),
SizedBox(height: 12),
// 图片网格
if (post['images'] > 0) _buildImageGrid(post['images']),
SizedBox(height: 12),
// 互动按钮行
Row(
children: [
// 点赞按钮
Expanded(
child: _buildActionButton(
icon: Icons.thumb_up_outlined,
label: '${post['likes']}',
onTap: () {},
),
),
// 评论按钮
Expanded(
child: _buildActionButton(
icon: Icons.comment_outlined,
label: '${post['comments']}',
onTap: () {},
),
),
// 分享按钮
Expanded(
child: _buildActionButton(
icon: Icons.share_outlined,
label: '分享',
onTap: () {},
),
),
],
),
],
),
);
}
Widget _buildImageGrid(int imageCount) {
if (imageCount == 1) {
// 单张图片
return Container(
height: 200,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Center(
child: Icon(Icons.image, size: 50, color: Colors.grey),
),
);
} else if (imageCount <= 4) {
// 2-4张图片,使用2x2网格
return GridView.count(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
crossAxisCount: 2,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
childAspectRatio: 1,
children: List.generate(imageCount, (index) => Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
child: Center(
child: Icon(Icons.image, color: Colors.grey),
),
)),
);
} else {
// 5张以上图片,使用3x3网格
return GridView.count(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
crossAxisCount: 3,
crossAxisSpacing: 4,
mainAxisSpacing: 4,
childAspectRatio: 1,
children: List.generate(
imageCount > 9 ? 9 : imageCount,
(index) => Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
child: Stack(
children: [
Center(
child: Icon(Icons.image, color: Colors.grey),
),
if (index == 8 && imageCount > 9)
Container(
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(4),
),
child: Center(
child: Text(
'+${imageCount - 9}',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
),
);
}
}
Widget _buildActionButton({
required IconData icon,
required String label,
required VoidCallback onTap,
}) {
return InkWell(
onTap: onTap,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, size: 20, color: Colors.grey[600]),
SizedBox(width: 4),
Text(
label,
style: TextStyle(
color: Colors.grey[600],
fontSize: 14,
),
),
],
),
),
);
}
}
📚 学习总结
通过这一章的学习,你已经掌握了:
🧱 常用布局Widget
- ListView:创建可滚动的列表
- GridView:创建网格布局
- Stack:创建层叠布局
- Wrap:创建自动换行布局
🎨 实践能力
- 组合布局:能够组合多种布局创建复杂界面
- 响应式设计:理解如何适配不同屏幕尺寸
- 实际应用:完成了社交媒体界面的制作
🚀 下一步
接下来我们将学习状态管理,了解如何让应用变得更加动态和交互性更强。
每篇文章并不长,这个系列是由浅到深来设计的。如果文章对您有帮助,麻烦动动发财的小手点赞、关注和收藏,您的反馈将是作者不断更新的动力🙏🏻