Flutter实战:阅读进度追踪应用开发指南
前言
阅读进度追踪是一款帮助读者管理阅读计划、记录阅读进度的实用应用。这个项目涵盖了数据建模、状态管理、数据持久化、统计分析等核心技术,是学习Flutter应用开发的优秀实践案例。
效果预览



应用特性:
- 书籍分类管理(在读/已完成/想读)
- 阅读进度追踪
- 阅读统计分析
- 评分和笔记功能
- 数据本地持久化
技术架构
业务层
数据层
UI层
TabBar分类
书籍列表
详情页面
进度编辑
Book模型
SharedPreferences
JSON序列化
进度计算
统计分析
状态管理
数据更新
核心数据模型
书籍状态枚举
dart
enum BookStatus {
reading, // 在读
completed, // 已完成
wishlist, // 想读
}
书籍模型
dart
class Book {
String id;
String title;
String author;
int totalPages;
int currentPage;
BookStatus status;
DateTime startDate;
DateTime? finishDate;
String? notes;
int rating; // 0-5星
Book({
required this.id,
required this.title,
required this.author,
required this.totalPages,
this.currentPage = 0,
this.status = BookStatus.wishlist,
DateTime? startDate,
this.finishDate,
this.notes,
this.rating = 0,
}) : startDate = startDate ?? DateTime.now();
// 计算属性
double get progress => totalPages > 0 ? currentPage / totalPages : 0;
int get remainingPages => totalPages - currentPage;
int get readingDays => DateTime.now().difference(startDate).inDays + 1;
double get averagePagesPerDay => readingDays > 0 ? currentPage / readingDays : 0;
}
统计计算
进度百分比
Progress=CurrentPageTotalPages×100%Progress = \frac{CurrentPage}{TotalPages} \times 100\%Progress=TotalPagesCurrentPage×100%
dart
double get progress => totalPages > 0 ? currentPage / totalPages : 0;
平均阅读速度
AverageSpeed=CurrentPageReadingDaysAverageSpeed = \frac{CurrentPage}{ReadingDays}AverageSpeed=ReadingDaysCurrentPage
dart
double get averagePagesPerDay => readingDays > 0 ? currentPage / readingDays : 0;
预计完成时间
EstimatedDays=RemainingPagesAverageSpeedEstimatedDays = \frac{RemainingPages}{AverageSpeed}EstimatedDays=AverageSpeedRemainingPages
dart
int estimatedDaysToFinish = (remainingPages / averagePagesPerDay).ceil();
数据持久化
JSON序列化
dart
class Book {
Map<String, dynamic> toJson() => {
'id': id,
'title': title,
'author': author,
'totalPages': totalPages,
'currentPage': currentPage,
'status': status.index,
'startDate': startDate.toIso8601String(),
'finishDate': finishDate?.toIso8601String(),
'notes': notes,
'rating': rating,
};
factory Book.fromJson(Map<String, dynamic> json) => Book(
id: json['id'],
title: json['title'],
author: json['author'],
totalPages: json['totalPages'],
currentPage: json['currentPage'] ?? 0,
status: BookStatus.values[json['status'] ?? 0],
startDate: DateTime.parse(json['startDate']),
finishDate: json['finishDate'] != null
? DateTime.parse(json['finishDate'])
: null,
notes: json['notes'],
rating: json['rating'] ?? 0,
);
}
SharedPreferences存储
dart
Future<void> _saveBooks() async {
final prefs = await SharedPreferences.getInstance();
final booksJson = jsonEncode(_books.map((e) => e.toJson()).toList());
await prefs.setString('books', booksJson);
}
Future<void> _loadBooks() async {
final prefs = await SharedPreferences.getInstance();
final booksJson = prefs.getString('books');
if (booksJson != null) {
final List<dynamic> list = jsonDecode(booksJson);
setState(() {
_books = list.map((e) => Book.fromJson(e)).toList();
});
}
}
TabBar分类管理
三标签布局
dart
TabBar(
controller: _tabController,
tabs: const [
Tab(text: '在读'),
Tab(text: '已完成'),
Tab(text: '想读'),
],
)
TabBarView(
controller: _tabController,
children: [
_buildBookList(BookStatus.reading),
_buildBookList(BookStatus.completed),
_buildBookList(BookStatus.wishlist),
],
)
状态过滤
dart
List<Book> _getBooksByStatus(BookStatus status) {
return _books.where((book) => book.status == status).toList();
}
书籍卡片设计
卡片布局
dart
Widget _buildBookCard(Book book) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题和作者
Text(book.title, style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
Text(book.author, style: TextStyle(color: Colors.grey)),
// 进度条
if (book.status != BookStatus.wishlist) ...[
LinearProgressIndicator(
value: book.progress,
backgroundColor: Colors.grey.shade200,
valueColor: AlwaysStoppedAnimation(
book.status == BookStatus.completed ? Colors.green : Colors.deepOrange,
),
),
Text('${book.currentPage} / ${book.totalPages} 页'),
],
// 统计信息
if (book.status == BookStatus.reading) ...[
Text('已读 ${book.readingDays} 天'),
Text('平均 ${book.averagePagesPerDay.toStringAsFixed(1)} 页/天'),
],
],
),
),
);
}
进度条颜色
开始阅读
完成
想读
在读 - 橙色
已完成 - 绿色
详情页功能
状态切换
dart
SegmentedButton<BookStatus>(
segments: const [
ButtonSegment(
value: BookStatus.wishlist,
label: Text('想读'),
icon: Icon(Icons.bookmark_border),
),
ButtonSegment(
value: BookStatus.reading,
label: Text('在读'),
icon: Icon(Icons.menu_book),
),
ButtonSegment(
value: BookStatus.completed,
label: Text('完成'),
icon: Icon(Icons.check_circle),
),
],
selected: {_book.status},
onSelectionChanged: (Set<BookStatus> newSelection) {
_changeStatus(newSelection.first);
},
)
进度更新
dart
void _updateProgress(int newPage) {
setState(() {
_book.currentPage = newPage.clamp(0, _book.totalPages);
// 自动更新状态
if (_book.currentPage > 0 && _book.status == BookStatus.wishlist) {
_book.status = BookStatus.reading;
_book.startDate = DateTime.now();
}
if (_book.currentPage >= _book.totalPages &&
_book.status == BookStatus.reading) {
_book.status = BookStatus.completed;
_book.finishDate = DateTime.now();
}
});
widget.onUpdate(_book);
}
评分系统
dart
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(5, (index) {
return IconButton(
icon: Icon(
index < _book.rating ? Icons.star : Icons.star_border,
color: Colors.amber,
size: 36,
),
onPressed: () => _updateRating(index + 1),
);
}),
)
阅读统计
统计指标
| 指标 | 计算方式 | 说明 |
|---|---|---|
| 进度 | currentPage / totalPages | 完成百分比 |
| 已读天数 | now - startDate | 阅读持续时间 |
| 剩余页数 | totalPages - currentPage | 还需阅读 |
| 平均速度 | currentPage / readingDays | 每天阅读页数 |
| 预计完成 | remainingPages / averageSpeed | 还需多少天 |
统计展示
dart
Widget _buildStatRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(color: Colors.grey.shade600)),
Text(value, style: TextStyle(fontWeight: FontWeight.bold)),
],
),
);
}
// 使用
_buildStatRow('已读天数', '${_book.readingDays} 天'),
_buildStatRow('剩余页数', '${_book.remainingPages} 页'),
_buildStatRow('平均速度', '${_book.averagePagesPerDay.toStringAsFixed(1)} 页/天'),
_buildStatRow('预计完成', '${estimatedDays} 天后'),
笔记功能
多行文本输入
dart
TextField(
controller: _notesController,
maxLines: 5,
decoration: const InputDecoration(
hintText: '记录你的阅读感受...',
border: OutlineInputBorder(),
),
onChanged: (_) => _updateNotes(),
)
实时保存
dart
void _updateNotes() {
setState(() {
_book.notes = _notesController.text;
});
widget.onUpdate(_book);
}
数据流转
存储 详情页 列表页 用户 存储 详情页 列表页 用户 添加书籍 保存数据 点击书籍 打开详情 更新进度 回调更新 保存数据 删除书籍 回调删除 保存数据 刷新列表
空状态处理
dart
if (books.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.menu_book,
size: 64,
color: Colors.grey.shade300,
),
const SizedBox(height: 16),
Text(
'还没有在读的书籍',
style: TextStyle(color: Colors.grey.shade400, fontSize: 16),
),
Text(
'点击右下角添加书籍',
style: TextStyle(color: Colors.grey.shade400, fontSize: 14),
),
],
),
);
}
扩展思路
阅读追踪扩展
数据分析
阅读时长统计
月度阅读报告
年度阅读总结
阅读趋势图
社交功能
书评分享
好友推荐
阅读小组
读书打卡
内容增强
书籍封面
ISBN扫描
豆瓣API
在线书库
提醒功能
阅读提醒
目标设定
每日打卡
完成庆祝
阅读目标系统(扩展)
目标设定
dart
class ReadingGoal {
int booksPerYear;
int pagesPerDay;
int minutesPerDay;
bool isAchieved(List<Book> books) {
final thisYear = books.where((b) =>
b.finishDate?.year == DateTime.now().year
).length;
return thisYear >= booksPerYear;
}
}
进度可视化
dart
CircularProgressIndicator(
value: completedBooks / goalBooks,
backgroundColor: Colors.grey.shade200,
valueColor: AlwaysStoppedAnimation(Colors.green),
)
性能优化
1. 列表优化
dart
ListView.builder(
itemCount: books.length,
itemBuilder: (context, index) => _buildBookCard(books[index]),
)
使用 ListView.builder 而非 ListView,实现懒加载。
2. 数据缓存
dart
// 只在需要时保存
void _updateBook(Book book) {
setState(() {
final index = _books.indexWhere((b) => b.id == book.id);
if (index != -1) {
_books[index] = book;
}
});
_saveBooks(); // 立即保存
}
3. 状态管理
dart
// 使用回调而非全局状态
BookDetailPage(
book: book,
onUpdate: _updateBook,
onDelete: _deleteBook,
)
总结
这个阅读进度追踪应用实现了完整的书籍管理功能,核心技术点包括:
- 数据建模 - 完善的Book模型和计算属性
- JSON序列化 - toJson/fromJson实现数据持久化
- TabBar导航 - 三标签分类管理
- 统计分析 - 多维度阅读数据统计
- 状态管理 - 回调模式实现页面间通信
通过这个项目,可以学习到实用应用开发的完整流程,从数据建模到UI设计,从统计分析到用户体验,是Flutter开发的优秀实践案例。
阅读是一种习惯,记录是一种坚持。希望这个应用能帮助你养成良好的阅读习惯!📚
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net