Flutter for OpenHarmony艺考真题题库app实战+收藏夹实现
摘要:本文介绍了艺考学习应用中收藏夹功能的设计与实现,重点围绕易用性、可视化和可管理三大原则。采用Flutter框架开发,使用StatefulWidget管理状态,实现收藏统计、分类筛选、排序等功能。关键技术包括:异步数据加载、空状态引导界面、分类统计展示、卡片式列表渲染等。设计注重用户体验,通过视觉分层、操作指引和性能优化,帮助用户高效管理高频考点和易错题目。整体架构清晰,代码可维护性强,适配O

收藏夹是艺考学习应用中的核心功能模块,其核心价值在于帮助用户沉淀高频考点、易错题目,提升复习效率。本次实现的收藏夹页面围绕「易用性、可视化、可管理」三大设计原则,涵盖收藏统计、分类筛选、排序、空状态引导等全场景功能,适配OpenHarmony系统的交互规范与UI风格。
收藏夹架构设计
收藏夹页面需动态响应收藏数据的增删改操作,因此选择StatefulWidget作为基础组件,核心设计要点:
- 状态管理:通过State类维护核心数据,保证操作后UI实时刷新
- 生命周期:在
initState中初始化数据,避免页面加载空白 - 数据解耦:收藏列表与排序类型分离,便于后续功能扩展
class FavoriteQuestionsPage extends StatefulWidget {
const FavoriteQuestionsPage({Key? key}) : super(key: key);
State<FavoriteQuestionsPage> createState() =>
_FavoriteQuestionsPageState();
}
定义页面状态类,聚焦核心数据管理,设计考量如下:
- 核心字段:仅保留收藏列表和排序类型,降低状态复杂度
- 初始化逻辑:页面创建时自动加载收藏数据,保证数据时效性
class _FavoriteQuestionsPageState extends State<FavoriteQuestionsPage> {
List<Question> favoriteQuestions = [];
String sortType = 'time'; // time/ difficulty/ category
void initState() {
super.initState();
_loadFavoriteQuestions();
}
}
收藏数据加载
收藏数据加载需兼顾本地缓存与云端同步,演示阶段采用模拟数据,核心设计要点:
- 数据来源:实际项目中需关联用户账户,支持跨设备同步
- 性能优化:异步加载数据,避免阻塞UI线程
- 数据过滤:加载时剔除失效题目,保证数据有效性
void _loadFavoriteQuestions() {
// 模拟加载:取前3条作为收藏数据
final allQuestions = MockData.getQuestions();
favoriteQuestions = allQuestions.take(3).toList();
}
空状态界面
空状态是提升用户体验的关键环节,设计时需注意:
- 视觉引导:大尺寸图标+分层文字,清晰传递无收藏状态
- 操作指引:明确告知收藏触发方式,降低用户学习成本
- 风格统一:适配OpenHarmony中性色规范,保持视觉一致性
Widget _buildEmptyState() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.star_border, size: 100.w, color: Colors.grey[400]),
SizedBox(height: 16.h),
Text('暂无收藏题目', style: TextStyle(fontSize: 18.sp)),
],
),
);
}
补充空状态的引导文案,强化操作指引:
- 二级提示:明确收藏操作路径,引导用户完成首次收藏
- 间距控制:通过
SizedBox保证元素间距,符合移动端交互习惯
SizedBox(height: 8.h),
Text(
'在答题时点击收藏按钮即可收藏',
style: TextStyle(fontSize: 14.sp, color: Colors.grey[500]),
),
],
),
);
}
收藏统计功能
收藏统计模块帮助用户快速掌握收藏数据分布,设计要点:
- 视觉区分:浅橙色容器突出统计区域,不抢夺核心内容焦点
- 布局适配:
Wrap组件实现标签流式布局,适配不同屏幕宽度 - 数据维度:按分类统计数量,帮助用户定位高频复习方向
Widget _buildStatistics() {
final categoryStats = _getCategoryStatistics();
return Container(
margin: EdgeInsets.all(16.w),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.orange[50],
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('收藏统计', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
SizedBox(height: 12.h),
统计标签的展示逻辑,优化交互体验:
- 样式设计:浅橙色背景+圆角,符合移动端标签设计趋势
- 信息传递:分类名称+数量组合,直观展示统计结果
- 间距控制:保证标签间呼吸感,避免视觉拥挤
Wrap(
spacing: 8.w,
runSpacing: 8.h,
children: categoryStats.entries.map((entry) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: Colors.orange[100],
borderRadius: BorderRadius.circular(16.r),
),
child: Text('${entry.key}: ${entry.value}'),
);
}).toList(),
),
],
),
);
}
分类统计实现
分类统计的核心是遍历收藏列表完成计数,设计要点:
- 数据结构:
Map存储分类-数量键值对,查询效率高 - 空值处理:
??运算符避免首次统计时的空指针异常 - 逻辑简洁:遍历累加,保证统计逻辑易理解、易维护
Map<String, int> _getCategoryStatistics() {
final Map<String, int> stats = {};
for (final question in favoriteQuestions) {
stats[question.category] = (stats[question.category] ?? 0) + 1;
}
return stats;
}
收藏列表实现
收藏列表采用ListView.builder实现懒加载,核心设计:
- 性能优化:仅渲染可见区域卡片,降低内存占用
- 结构分层:先展示统计模块,再展示列表,符合用户认知习惯
- 卡片容器:
Card组件包裹内容,提升视觉层次感
Widget _buildFavoriteList() {
return Column(
children: [
_buildStatistics(),
Expanded(
child: ListView.builder(
itemCount: favoriteQuestions.length,
itemBuilder: (context, index) {
final question = favoriteQuestions[index];
return Card(
margin: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
child: ListTile(
收藏卡片核心信息展示,兼顾信息密度与可读性:
- 左侧标识:圆形头像+星星图标,直观标记收藏状态
- 标题处理:限制行数+文字截断,避免标题过长错乱
- 副标题分层:展示分类、科目,满足快速筛选需求
leading: CircleAvatar(
backgroundColor: Colors.orange[100],
child: Icon(Icons.star, color: Colors.orange[600]),
),
title: Text(
question.title,
style: TextStyle(fontSize: 16.sp),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('${question.category} - ${question.subject}'),
收藏卡片辅助信息展示,丰富数据维度:
- 难度标记:通过Chip组件可视化展示题目难度
- 时间信息:年份+收藏时间,帮助用户回忆收藏场景
- 间距控制:合理留白,提升信息可读性
Row(
children: [
_buildDifficultyChip(question.difficulty),
SizedBox(width: 8.w),
Text('${question.year}年'),
SizedBox(width: 8.w),
Text('收藏于 ${_getFavoriteTime(index)}'),
],
),
],
),
收藏卡片快捷操作按钮,优化操作路径:
- 轻量化设计:仅展示图标,节省页面空间
- 功能直达:练习、取消收藏按钮,满足高频操作需求
- 路由跳转:点击卡片/按钮跳转对应页面,逻辑清晰
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: () {
Navigator.pushNamed(context, '/exam', arguments: '收藏练习');
},
),
IconButton(
icon: const Icon(Icons.star),
onPressed: () => _removeFavorite(question.id),
),
],
),
onTap: () => Navigator.pushNamed(context, '/question_detail', arguments: question),
),
);
},
),
),
],
);
}
排序功能实现
排序功能入口设计在AppBar,符合移动端操作习惯:
- 入口位置:AppBar右侧,易发现、易操作
- 选项设计:覆盖时间、难度、分类三大核心排序维度
- 状态同步:选择后立即更新状态并触发排序
actions: [
PopupMenuButton<String>(
onSelected: (value) {
setState(() {
sortType = value;
_sortQuestions();
});
},
itemBuilder: (context) => [
const PopupMenuItem(value: 'time', child: Text('按时间排序')),
const PopupMenuItem(value: 'difficulty', child: Text('按难度排序')),
const PopupMenuItem(value: 'category', child: Text('按分类排序')),
],
),
],
排序逻辑实现
排序逻辑根据不同维度定制比较规则,设计要点:
- 维度适配:不同排序类型对应不同比较逻辑
- 难度排序:自定义优先级(简单<中等<困难),符合用户认知
- 即时刷新:
setState触发UI重建,排序结果实时展示
void _sortQuestions() {
setState(() {
switch (sortType) {
case 'time':
favoriteQuestions.sort((a, b) => a.id.compareTo(b.id));
break;
case 'difficulty':
final order = {'简单': 1, '中等': 2, '困难': 3};
favoriteQuestions.sort((a, b) => order[a.difficulty]!.compareTo(order[b.difficulty]!));
break;
case 'category':
favoriteQuestions.sort((a, b) => a.category.compareTo(b.category));
break;
}
});
}
收藏时间显示
收藏时间采用相对时间展示,提升用户体验:
- 友好性:「X天前」比绝对时间更符合阅读习惯
- 模拟数据:演示阶段用索引模拟,实际需存储真实时间戳
- 本地化:适配OpenHarmony本地化API,兼容多语言
String _getFavoriteTime(int index) {
// 模拟收藏时间:索引*2+1天前
final days = index * 2 + 1;
return '${days}天前';
}
取消收藏功能
取消收藏需保证操作安全且反馈及时,设计要点:
- 数据更新:移除对应题目,保证列表数据一致性
- 视觉反馈:SnackBar提示操作结果,提升用户感知
- 防误操作:可扩展确认弹窗,降低误操作概率
void _removeFavorite(String questionId) {
setState(() {
favoriteQuestions.removeWhere((q) => q.id == questionId);
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已取消收藏')),
);
}
用户体验优化
为了提升用户体验,我们在收藏卡片上添加了快捷操作按钮。用户可以直接点击练习按钮进入收藏题目练习,或者点击星标按钮取消收藏。
数据持久化考虑
在实际应用中,收藏数据需要持久化存储。我们可以使用SharedPreferences或数据库来存储收藏信息,确保数据不会丢失。
性能优化
收藏列表使用ListView.builder来优化性能,确保只有可见的收藏题目会被渲染。同时,我们使用const构造函数减少不必要的重建。
通过以上实现,我们创建了一个功能完善、用户友好的收藏夹页面。这个页面不仅能够帮助用户管理收藏题目,还提供了丰富的统计信息和排序功能,为用户的学习提供了便利。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)