AtomGit Flutter 鸿蒙客户端: 情绪日记的三 Tab 架构
·

Tab 是移动端最高效的信息组织方式之一。本文详解 DiaryPage 的三 Tab 架构设计与数据共享。
一、Tab 配置
// diary_page.dart
class _DiaryPageState extends State<DiaryPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
widget.moodStorage.addListener(_loadMoods);
_loadMoods();
}
}
SingleTickerProviderStateMixin 提供 Ticker(帧回调),TabController 需要它来驱动标签页的切换动画。
二、TabBar + TabBarView
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('情绪日记'),
bottom: TabBar(
controller: _tabController,
tabs: const [
Tab(text: '记录'), // Tab 0
Tab(text: '时间线'), // Tab 1
Tab(text: '统计'), // Tab 2
],
),
),
body: TabBarView(
controller: _tabController,
children: [
_buildRecordTab(),
_buildTimelineTab(),
_buildStatsTab(),
],
),
);
}
★ Insight ─────────────────────────────────────
将 TabBar 放在 AppBar 的bottom属性中,使标签页成为导航栏的一部分——这是 Material Design 的标准模式。用户在切换标签时,标签栏始终可见,不会随内容滚动消失。─────────────────────────────────────────────────
三、三 Tab 的数据流
MoodStorage (单例)
↓ addListener(_loadMoods)
_loadMoods() {
_allMoods = storage.getAll(); ← 所有 Tab 共用
_weekMoods = storage.getByWeek(); ← 统计 Tab 专用
}
↓ setState()
Tab 0: _selectedMood, _noteController (本地状态)
Tab 1: _allMoods (共享数据)
Tab 2: _weekMoods (共享数据)
关键设计:数据在 _loadMoods() 中统一加载,然后所有 Tab 都能访问。
四、Tab 0:记录页
Widget _buildRecordTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
// 日期选择器
Row(
children: [
IconButton(icon: Icons.chevron_left, onPressed: goToPrevDay),
Text(_formatDate(_selectedDate)),
IconButton(icon: Icons.chevron_right, onPressed: goToNextDay),
],
),
// 情绪选择器
MoodPicker(selected: _selectedMood, onChanged: (m) => setState(...)),
// 备注输入
TextField(controller: _noteController, maxLength: 500, maxLines: 3),
// 保存按钮
ElevatedButton(onPressed: _saveMood),
],
),
);
}
五、Tab 间联动:编辑功能
void _editMood(MoodEntry mood) {
if (mood.id == null) return;
_noteController.text = mood.note ?? '';
setState(() {
_selectedMood = mood.moodType;
_selectedDate = mood.createdAt;
_editingId = mood.id;
});
_tabController.animateTo(0); // 自动切换到"记录"Tab
}
从时间线(Tab 1)底部弹窗点击"编辑"→ 自动跳转到记录 Tab(Tab 0)并回填数据。TabController 的 animateTo(0) 提供了平滑的切换动画。
六、Tab 2:统计页
Widget _buildStatsTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
const Text('本周心情'),
const SizedBox(height: 16),
MoodChart(weekMoods: _weekMoods),
const SizedBox(height: 16),
Text(MoodChart.summaryText(_weekMoods)),
],
),
);
}
简洁的布局:标题 + 图表 + AI 式总结文字。
七、生命周期清理
void dispose() {
widget.moodStorage.removeListener(_loadMoods);
_tabController.dispose();
_noteController.dispose();
super.dispose();
}
三个资源都要清理:数据监听器、Tab 控制器、文本控制器。
小结
三 Tab 架构是移动端信息密集型页面的标准解法。E-Brufen 的实现体现了三个关键原则:统一数据加载(一个 _loadMoods 服务所有 Tab)、Tab 间联动(编辑跳转回记录)、资源清理(三个 dispose)。
作者简介:E-Brufen Dev,Flutter & 鸿蒙开发者,专注于跨平台移动应用开发与心理健康数字化,项目地址:AtomGit - E-Brufen。
更多推荐

所有评论(0)