Flutter for OpenHarmony 社团管理App实战 - 我的活动实现
本文介绍了如何实现一个用户活动列表页面,展示用户已报名的所有活动。页面采用无状态Widget设计,通过Provider获取数据。主要功能点包括: 页面采用Material Design风格,使用Scaffold搭建基础结构,包含标题栏和活动列表 使用Consumer监听数据变化,自动更新活动列表显示 空状态处理显示友好提示,包含图标和文字说明 活动列表使用ListView.builder实现高效渲

我的活动页面展示用户已报名参加的所有活动,方便用户查看和管理自己的活动安排。这篇文章带大家实现我的活动列表模块。
页面整体设计
我的活动页面以列表形式展示用户参与的活动,每个卡片显示日期、标题、社团、地点和状态信息。
页面采用StatelessWidget实现:
class MyActivitiesPage extends StatelessWidget {
const MyActivitiesPage({super.key});
页面不需要维护内部状态,数据从Provider获取。
const构造函数可以让Flutter复用Widget实例。
导入依赖包
在文件开头导入必要的依赖:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
material.dart提供Material Design风格的组件。
provider用于状态管理,intl用于日期格式化。
导入项目内部文件:
import '../../providers/app_provider.dart';
import 'activity_detail_page.dart';
app_provider包含用户活动列表数据。
activity_detail_page是活动详情页面。
构建页面骨架
使用Scaffold搭建基本结构:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('我的活动')
),
Scaffold提供标准的Material页面结构。
AppBar显示页面标题"我的活动"。
监听数据变化
页面主体使用Consumer监听数据:
body: Consumer<AppProvider>(
builder: (context, provider, _) {
final myActivities = provider.myActivities;
Consumer自动订阅AppProvider的变化。
myActivities是用户已报名的活动列表。
空状态处理
没有活动时显示友好提示:
if (myActivities.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.event_busy,
size: 64,
color: Colors.grey
),
SizedBox(height: 16),
Text(
'暂未参加任何活动',
style: TextStyle(
color: Colors.grey,
fontSize: 16
)
),
],
),
);
}
event_busy图标直观表示没有活动。
灰色文字提示用户当前状态。
构建活动列表
使用ListView.builder构建列表:
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: myActivities.length,
ListView.builder采用懒加载机制。
padding设置16像素内边距。
活动卡片容器
每个活动用Card包裹:
itemBuilder: (context, index) {
final activity = myActivities[index];
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => ActivityDetailPage(
activity: activity
)
)
),
Card提供Material风格的卡片效果。
InkWell添加水波纹点击效果。
卡片内容布局
卡片内部使用Row横向布局:
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Padding设置16像素内边距。
Row让日期区和信息区横向排列。
日期显示区
左侧显示活动日期:
Container(
width: 60,
height: 60,
decoration: BoxDecoration(
color: const Color(0xFF4A90E2)
.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
DateFormat('dd')
.format(activity.startTime),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF4A90E2)
)
),
日期区用蓝色背景突出显示。
日期数字用大号粗体字。
月份显示:
Text(
DateFormat('MM月')
.format(activity.startTime),
style: const TextStyle(
fontSize: 12,
color: Color(0xFF4A90E2)
)
),
],
),
),
const SizedBox(width: 16),
月份用小号字显示在日期下方。
这种日历式的日期展示很直观。
活动信息区
中间区域显示活动详细信息:
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
activity.title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16
)
),
const SizedBox(height: 4),
Text(
activity.clubName,
style: const TextStyle(
color: Color(0xFF4A90E2),
fontSize: 13
)
),
标题用粗体16像素字号突出显示。
社团名称用蓝色显示,和日期区呼应。
地点信息:
const SizedBox(height: 4),
Row(
children: [
const Icon(
Icons.location_on,
size: 14,
color: Colors.grey
),
const SizedBox(width: 4),
Expanded(
child: Text(
activity.location,
style: const TextStyle(
fontSize: 12,
color: Colors.grey
),
overflow: TextOverflow.ellipsis
)
),
],
),
],
),
),
定位图标配合地点信息。
Expanded让地点文字占据剩余空间。
状态标签
右侧显示活动状态:
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4
),
decoration: BoxDecoration(
color: activity.status == '已结束'
? Colors.grey.withOpacity(0.1)
: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(
activity.status,
style: TextStyle(
color: activity.status == '已结束'
? Colors.grey
: Colors.green,
fontSize: 12
)
),
),
],
),
),
),
);
},
);
},
),
);
}
}
已结束用灰色,进行中用绿色。
状态标签帮助用户快速判断活动时效。
日期展示的设计
日历式的日期展示有几个优点。
首先视觉上很直观,用户一眼就能看到日期。
其次和传统日历的展示方式一致。
用户不需要学习就能理解。
状态颜色的意义
绿色表示活动还在进行或即将开始。
灰色表示活动已经结束。
这种颜色区分让用户快速判断活动状态。
不需要阅读文字就能获取信息。
列表性能优化
ListView.builder的懒加载机制提供基础性能保障。
只有可见区域的卡片才会被创建。
如果用户参加了很多活动,这种方式可以显著提升性能。
滚动时新的卡片才会被创建。
筛选功能扩展
可以按状态筛选活动:
final statusFilter = ['全部', '即将开始', '进行中', '已结束'];
ChoiceChip(
label: Text(status),
selected: selectedStatus == status,
onSelected: (selected) {
setState(() {
selectedStatus = status;
});
},
)
ChoiceChip实现单选筛选效果。
用户可以只看即将开始的活动。
日历视图
可以添加日历视图展示活动:
TableCalendar(
focusedDay: DateTime.now(),
firstDay: DateTime(2020),
lastDay: DateTime(2030),
eventLoader: (day) {
return myActivities.where(
(a) => isSameDay(a.startTime, day)
).toList();
},
)
日历视图让用户直观看到活动分布。
有活动的日期会显示标记点。
提醒功能
可以为活动设置提醒:
IconButton(
icon: Icon(
activity.hasReminder
? Icons.notifications_active
: Icons.notifications_none
),
onPressed: () {
// 设置提醒
},
)
提醒图标显示在卡片上。
用户可以为重要活动设置提醒。
签到功能
活动开始时可以签到:
if (activity.status == '进行中')
ElevatedButton(
onPressed: () {
// 签到逻辑
},
child: Text('签到'),
)
签到按钮只在活动进行中显示。
签到后可以获得积分奖励。
小结
我的活动页面通过列表形式展示用户参与的活动,每个卡片显示日历式日期、标题、社团、地点和状态。已结束的活动用灰色标识,进行中的用绿色标识。点击卡片可进入活动详情页面。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)