Flutter for OpenHarmony 看书管理记录App实战:阅读报告实现
本文介绍了一个阅读报告页面的Flutter实现,主要包含以下功能模块: 头部标题卡片 - 采用渐变背景设计,显示月份和"阅读报告"标题,并带有激励性文案 数据亮点卡片 - 三列并列显示阅读天数、完成书籍数和阅读时长等核心数据 阅读趋势折线图 - 以可视化方式展示用户的阅读习惯变化趋势 本月最爱书籍 - 展示用户最常阅读的书籍 阅读习惯分析 - 提供用户的阅读偏好分析 页面设计参
阅读报告页面是统计分析的进阶版,它不仅展示数据,还会给出一些有趣的分析结论,比如"你已超越85%的读者"这样的激励信息。这个页面的设计目标是让用户有成就感,愿意继续保持阅读习惯。
做这个页面的时候,我参考了一些运动类App的年度报告设计,它们都很擅长用数据讲故事,让用户觉得自己很厉害。
依赖引入
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fl_chart/fl_chart.dart';
这个页面也用到了 fl_chart,主要是用折线图展示阅读趋势。
页面主体结构
class ReadingReportPage extends StatelessWidget {
const ReadingReportPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFFDF8F3),
appBar: AppBar(
title: const Text('阅读报告'),
backgroundColor: const Color(0xFF5B4636),
foregroundColor: Colors.white,
actions: [
IconButton(icon: const Icon(Icons.share), onPressed: () {}),
],
),
AppBar 右上角有个分享按钮,用户可以把自己的阅读报告分享到社交平台。这个功能在实际项目中需要接入分享SDK。
页面内容布局
body: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(),
SizedBox(height: 20.h),
_buildHighlights(),
SizedBox(height: 20.h),
_buildTrendChart(),
SizedBox(height: 20.h),
_buildTopBooks(),
SizedBox(height: 20.h),
_buildReadingHabits(),
],
),
),
);
}
页面分五个模块:头部标题、数据亮点、趋势图表、本月最爱、阅读习惯。每个模块都有自己的特色。
头部标题卡片
Widget _buildHeader() {
return Container(
padding: EdgeInsets.all(24.w),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF5B4636), Color(0xFF8B7355)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(16.r),
),
头部用渐变背景,从左上到右下,比单纯的水平渐变更有层次感。
标题内容
child: Column(
children: [
Text('2024年1月', style: TextStyle(
color: Colors.white70,
fontSize: 14.sp,
)),
SizedBox(height: 8.h),
Text('阅读报告', style: TextStyle(
color: Colors.white,
fontSize: 28.sp,
fontWeight: FontWeight.bold,
)),
标题分两行,上面是月份,下面是"阅读报告"四个大字。月份用半透明白色,报告标题用纯白加粗,字号 28,非常醒目。
激励文案
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.auto_awesome, color: Colors.amber, size: 20.sp),
SizedBox(width: 8.w),
Text('你已超越 85% 的读者', style: TextStyle(
color: Colors.amber,
fontSize: 14.sp,
)),
],
),
],
),
);
}
底部是一句激励文案,用琥珀色显示,前面加个星星图标。这种设计能给用户成就感,激励他们继续阅读。
这个百分比可以根据用户的实际阅读量计算,和其他用户对比得出。
数据亮点卡片
Widget _buildHighlights() {
return Row(
children: [
Expanded(child: _buildHighlightCard('阅读天数', '28', '天', Icons.calendar_today)),
SizedBox(width: 12.w),
Expanded(child: _buildHighlightCard('完成书籍', '4', '本', Icons.menu_book)),
SizedBox(width: 12.w),
Expanded(child: _buildHighlightCard('阅读时长', '32', '小时', Icons.timer)),
],
);
}
三个数据亮点并排显示,分别是阅读天数、完成书籍数、阅读时长。用 Expanded 让它们平分宽度。
亮点卡片组件
Widget _buildHighlightCard(String label, String value, String unit, IconData icon) {
return Container(
padding: EdgeInsets.all(14.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
children: [
Icon(icon, color: const Color(0xFF5B4636), size: 24.sp),
SizedBox(height: 8.h),
每个卡片顶部是一个图标,用主题色显示。图标能让用户快速识别这是什么数据。
数值显示
RichText(
text: TextSpan(
children: [
TextSpan(
text: value,
style: TextStyle(
fontSize: 22.sp,
fontWeight: FontWeight.bold,
color: const Color(0xFF3D2914),
),
),
TextSpan(
text: ' $unit',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
),
],
),
),
SizedBox(height: 4.h),
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 11.sp)),
],
),
);
}
数值用 RichText 实现,数字大号加粗,单位小号灰色。这样数字更突出,单位作为补充说明。
阅读趋势折线图
Widget _buildTrendChart() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('阅读趋势', style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: const Color(0xFF3D2914),
)),
SizedBox(height: 20.h),
趋势图用折线图展示,比柱状图更能体现数据的连续变化。
折线图配置
SizedBox(
height: 160.h,
child: LineChart(
LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: false,
horizontalInterval: 10,
getDrawingHorizontalLine: (v) => FlLine(
color: Colors.grey[200]!,
strokeWidth: 1,
),
),
LineChart 是 fl_chart 的折线图组件。网格线只显示水平线,间隔 10,用浅灰色绘制。
坐标轴设置
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: (v, m) => Text(
['1周', '2周', '3周', '4周'][v.toInt()],
style: TextStyle(fontSize: 11.sp, color: Colors.grey[600]),
),
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 35,
getTitlesWidget: (v, m) => Text(
'${v.toInt()}页',
style: TextStyle(fontSize: 10.sp, color: Colors.grey[500]),
),
),
),
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
),
borderData: FlBorderData(show: false),
底部显示周数,左边显示页数。顶部和右边的标题隐藏,让图表更简洁。
折线数据
lineBarsData: [
LineChartBarData(
spots: const [
FlSpot(0, 35),
FlSpot(1, 48),
FlSpot(2, 42),
FlSpot(3, 55),
],
isCurved: true,
color: const Color(0xFF5B4636),
barWidth: 3,
dotData: FlDotData(
show: true,
getDotPainter: (s, d, b, i) => FlDotCirclePainter(
radius: 4,
color: const Color(0xFF5B4636),
strokeWidth: 2,
strokeColor: Colors.white,
),
),
belowBarData: BarAreaData(
show: true,
color: const Color(0xFF5B4636).withOpacity(0.1),
),
),
],
),
),
),
],
),
);
}
折线用主题色,宽度 3,isCurved: true 让线条平滑。数据点用圆形标记,有白色描边。折线下方填充浅色区域,增加视觉层次。
本月最爱书籍
Widget _buildTopBooks() {
final books = [
{'title': '百年孤独', 'author': '加西亚·马尔克斯', 'hours': '12小时'},
{'title': '人类简史', 'author': '尤瓦尔·赫拉利', 'hours': '8小时'},
{'title': '三体', 'author': '刘慈欣', 'hours': '6小时'},
];
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
本月最爱展示阅读时间最长的三本书,用排行榜的形式呈现。
书籍列表渲染
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('本月最爱', style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: const Color(0xFF3D2914),
)),
SizedBox(height: 12.h),
...books.asMap().entries.map((e) => Padding(
padding: EdgeInsets.symmetric(vertical: 8.h),
child: Row(
children: [
Container(
width: 24.w,
height: 24.w,
decoration: BoxDecoration(
color: e.key == 0 ? Colors.amber : (e.key == 1 ? Colors.grey[400] : Colors.brown[300]),
shape: BoxShape.circle,
),
child: Center(
child: Text(
'${e.key + 1}',
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
fontWeight: FontWeight.bold,
),
),
),
),
排名用圆形徽章显示,第一名金色,第二名银色,第三名铜色。这种设计很有仪式感。
书籍信息
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(e.value['title'] as String, style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14.sp,
)),
Text(e.value['author'] as String, style: TextStyle(
color: Colors.grey[600],
fontSize: 12.sp,
)),
],
),
),
Text(e.value['hours'] as String, style: TextStyle(
color: const Color(0xFF5B4636),
fontSize: 13.sp,
)),
],
),
)).toList(),
],
),
);
}
每本书显示书名、作者、阅读时长。时长用主题色显示,作为排名的依据。
阅读习惯分析
Widget _buildReadingHabits() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('阅读习惯', style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: const Color(0xFF3D2914),
)),
SizedBox(height: 16.h),
阅读习惯模块分析用户的阅读行为,给出一些有趣的结论。
习惯数据展示
_buildHabitItem(Icons.wb_sunny, '最常阅读时段', '晚上 21:00-23:00'),
_buildHabitItem(Icons.timer, '平均每次阅读', '45 分钟'),
_buildHabitItem(Icons.speed, '平均阅读速度', '每小时 35 页'),
_buildHabitItem(Icons.favorite, '最爱分类', '文学'),
],
),
);
}
四个习惯数据:最常阅读时段、平均阅读时长、阅读速度、最爱分类。这些数据能帮助用户了解自己的阅读模式。
习惯项组件
Widget _buildHabitItem(IconData icon, String label, String value) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 8.h),
child: Row(
children: [
Icon(icon, color: const Color(0xFF5B4636), size: 20.sp),
SizedBox(width: 12.w),
Text(label, style: TextStyle(color: Colors.grey[600], fontSize: 13.sp)),
const Spacer(),
Text(value, style: TextStyle(fontWeight: FontWeight.w600, fontSize: 13.sp)),
],
),
);
}
}
每个习惯项是图标加标签加数值的布局,标签靠左,数值靠右。图标用主题色,让页面更有活力。
数据分析思路
阅读习惯的数据需要通过分析用户的阅读记录得出:
最常阅读时段:统计每条阅读记录的时间,找出出现频率最高的时间段。
平均阅读时长:所有阅读记录的时长总和除以记录数。
阅读速度:总页数除以总时长。
最爱分类:统计每个分类的阅读量,找出最多的那个。
小结
阅读报告页面通过数据可视化和文案设计,让用户对自己的阅读成就有清晰的认识。激励文案能增强用户的成就感,排行榜设计增加趣味性。
折线图展示趋势变化,习惯分析帮助用户了解自己。这些设计都是为了让用户愿意继续使用这个App记录阅读。
下一篇会讲阅读目标页面的实现,让用户可以设定和追踪自己的阅读目标。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)