Flutter for OpenHarmony 社团管理App实战 - 社团分类实现
这篇文章介绍了如何实现一个社团分类页面模块,主要包含以下内容: 页面设计采用网格布局展示6个分类卡片,每个卡片显示分类图标、名称和社团数量 技术实现使用StatelessWidget构建无状态页面,通过Provider管理数据状态 分类数据以List形式配置,包含名称、图标和颜色属性 页面主体使用GridView.builder构建2列网格布局,设置合理的间距和宽高比 每个分类卡片包含圆形图标背景

社团分类页面按类型展示社团,用户可以快速找到感兴趣的社团类别。这篇文章带大家实现社团分类模块。
页面整体设计
社团分类页面使用网格布局展示各个分类,每个分类卡片显示图标、名称和社团数量。
页面采用StatelessWidget实现:
class ClubCategoryPage extends StatelessWidget {
const ClubCategoryPage({super.key});
页面不需要维护内部状态,数据从Provider获取。
const构造函数可以让Flutter复用Widget实例。
导入依赖包
在文件开头导入必要的依赖:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
material.dart提供Material Design风格的组件。
provider用于状态管理和数据共享。
导入项目内部文件:
import '../../providers/app_provider.dart';
import 'club_detail_page.dart';
app_provider包含社团列表数据。
club_detail_page是社团详情页面。
定义分类数据
在build方法中定义分类配置:
Widget build(BuildContext context) {
final categories = [
{
'name': '科技',
'icon': Icons.computer,
'color': Colors.blue
},
{
'name': '艺术',
'icon': Icons.palette,
'color': Colors.purple
},
{
'name': '体育',
'icon': Icons.sports_basketball,
'color': Colors.orange
},
用List存储分类配置,每个分类包含名称、图标和颜色。
这种数据驱动的方式便于维护和扩展。
更多分类:
{
'name': '学术',
'icon': Icons.school,
'color': Colors.green
},
{
'name': '公益',
'icon': Icons.volunteer_activism,
'color': Colors.red
},
{
'name': '文娱',
'icon': Icons.movie,
'color': Colors.pink
},
];
六个分类涵盖了常见的社团类型。
每个分类用不同颜色区分,视觉上更丰富。
构建页面骨架
使用Scaffold搭建基本结构:
return Scaffold(
appBar: AppBar(
title: const Text('社团分类')
),
Scaffold提供标准的Material页面结构。
AppBar显示页面标题"社团分类"。
监听数据变化
页面主体使用Consumer监听数据:
body: Consumer<AppProvider>(
builder: (context, provider, _) {
Consumer自动订阅AppProvider的变化。
当社团数据变化时会自动更新分类下的社团数量。
网格布局
使用GridView.builder构建网格:
return GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 1.2,
),
itemCount: categories.length,
crossAxisCount设为2表示每行显示2个卡片。
crossAxisSpacing和mainAxisSpacing设置卡片间距。
childAspectRatio设为1.2让卡片稍微宽一些。
这个比例在手机屏幕上显示效果较好。
构建分类卡片
itemBuilder回调构建每个分类卡片:
itemBuilder: (context, index) {
final category = categories[index];
final clubCount = provider.clubs
.where((c) => c.category == category['name'])
.length;
从配置中取出当前分类信息。
统计该分类下的社团数量。
卡片容器:
return Card(
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => _CategoryClubsPage(
category: category['name'] as String,
color: category['color'] as Color,
),
),
);
},
Card提供Material风格的卡片效果。
点击后跳转到该分类的社团列表页面。
卡片内容
卡片内部纵向排列图标、名称和数量:
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: (category['color'] as Color)
.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
category['icon'] as IconData,
color: category['color'] as Color,
size: 32
),
),
图标放在圆形背景容器中。
背景色是分类颜色的10%透明度版本。
名称和数量:
const SizedBox(height: 12),
Text(
category['name'] as String,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16
)
),
const SizedBox(height: 4),
Text(
'$clubCount个社团',
style: const TextStyle(
color: Colors.grey,
fontSize: 12
)
),
],
),
),
);
},
);
},
),
);
}
}
分类名称用粗体16像素字号。
社团数量用灰色小字显示。
分类社团列表页
定义分类社团列表页面:
class _CategoryClubsPage extends StatelessWidget {
final String category;
final Color color;
const _CategoryClubsPage({
required this.category,
required this.color
});
页面接收分类名称和颜色作为参数。
下划线前缀表示这是私有类。
构建分类列表页
使用Scaffold搭建结构:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$category类社团')
),
body: Consumer<AppProvider>(
builder: (context, provider, _) {
final clubs = provider.clubs
.where((c) => c.category == category)
.toList();
标题显示分类名称加"类社团"后缀。
where方法筛选出该分类的社团。
空状态处理
没有社团时显示提示:
if (clubs.isEmpty) {
return const Center(
child: Text(
'暂无该类社团',
style: TextStyle(color: Colors.grey)
)
);
}
空状态处理是用户体验的重要环节。
灰色文字提示用户当前没有数据。
社团列表
使用ListView.builder构建列表:
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: clubs.length,
itemBuilder: (context, index) {
final club = clubs[index];
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: CircleAvatar(
backgroundColor: color.withOpacity(0.1),
child: Text(
club.name[0],
style: TextStyle(
color: color,
fontWeight: FontWeight.bold
)
),
),
头像使用分类颜色作为背景。
显示社团名称的首字母。
社团信息:
title: Text(club.name),
subtitle: Text(
'${club.memberCount}人 评分${club.rating}'
),
trailing: const Icon(Icons.chevron_right),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ClubDetailPage(club: club)
)
),
),
);
},
);
},
),
);
}
}
显示社团名称、成员数和评分。
点击后跳转到社团详情页面。
网格布局的优势
网格布局让分类一目了然。
用户可以快速浏览所有分类。
每行两个卡片在手机屏幕上显示效果好。
卡片大小适中,点击方便。
颜色区分的意义
每个分类用不同颜色区分有几个好处。
首先视觉上更丰富,不会显得单调。
其次帮助用户记忆和识别分类。
比如蓝色代表科技,橙色代表体育。
社团数量的展示
显示每个分类下的社团数量很有用。
用户可以了解各分类的社团分布情况。
数量多的分类可能更活跃。
用户可以据此选择感兴趣的分类。
分类配置的扩展
当前使用硬编码的分类配置。
实际项目中可以从服务器获取分类列表。
这样可以动态调整分类。
比如添加新分类或修改分类图标。
搜索功能
可以在分类页面添加搜索:
AppBar(
title: const Text('社团分类'),
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () {
// 打开搜索
},
),
],
)
搜索按钮放在AppBar右侧。
用户可以直接搜索社团名称。
热门分类
可以突出显示热门分类:
if (isHot)
Positioned(
right: 8,
top: 8,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(4),
),
child: Text('热门', style: TextStyle(color: Colors.white, fontSize: 10)),
),
)
热门标签显示在卡片右上角。
红色背景白色文字很醒目。
小结
社团分类页面通过网格布局展示各个分类,每个卡片显示图标、名称和社团数量。不同分类用不同颜色区分,视觉效果丰富。点击分类可进入该分类的社团列表页面。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)