Flutter for OpenHarmony 身体健康状况记录App实战 - 添加睡眠记录实现
睡眠记录功能摘要 该睡眠记录系统包含三个核心功能: 时间记录 - 提供入睡和起床时间选择器,支持24小时制显示 自动计算 - 实时计算并显示睡眠时长,处理跨午夜情况 质量评估 - 采用5级表情评分(很差到很好),比数字更直观 界面采用卡片式布局,包含: 紫色渐变显示的睡眠时长卡片 并排的入睡/起床时间选择卡片 表情评分质量选择区域 技术实现使用Flutter框架,通过状态管理实时更新UI,时间计算
#
前言
睡眠质量直接影响身体健康和精神状态。记录睡眠需要三个关键信息:入睡时间、起床时间、睡眠质量。系统会自动计算睡眠时长,用户还可以主观评价睡眠质量。
这个页面的交互比较丰富,会用到时间选择器和表情评分。
状态变量
睡眠记录需要入睡时间、起床时间和质量评分三个状态。
class AddSleepPage extends StatefulWidget {
const AddSleepPage({super.key});
State<AddSleepPage> createState() => _AddSleepPageState();
}
class _AddSleepPageState extends State<AddSleepPage> {
TimeOfDay _bedTime = const TimeOfDay(hour: 23, minute: 0);
TimeOfDay _wakeTime = const TimeOfDay(hour: 7, minute: 0);
int _quality = 3;
默认入睡时间 23:00,起床时间 7:00,睡眠时长 8 小时,是比较理想的作息。质量评分默认 3(良好)。
睡眠时长计算
根据入睡和起床时间自动计算睡眠时长。
String get _duration {
int mins = (_wakeTime.hour * 60 + _wakeTime.minute) -
(_bedTime.hour * 60 + _bedTime.minute);
if (mins < 0) mins += 24 * 60;
return '${mins ~/ 60}小时${mins % 60}分钟';
}
这个 getter 会在每次状态变化时重新计算。如果起床时间"早于"入睡时间(比如 23:00 睡到 7:00),说明跨越了午夜,需要加上 24 小时。
~/ 是 Dart 的整除运算符,% 是取余。比如 480 分钟 = 8 小时 0 分钟。
睡眠时长卡片
用渐变背景的卡片突出显示睡眠时长。
Widget _buildDurationCard() {
return Container(
width: double.infinity,
padding: EdgeInsets.all(28.w),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF845EC2), Color(0xFFA178DF)]
),
borderRadius: BorderRadius.circular(24.r),
),
child: Column(
children: [
Icon(Icons.nightlight_round, size: 40.w, color: Colors.white70),
SizedBox(height: 12.h),
Text('睡眠时长', style: TextStyle(
fontSize: 13.sp,
color: Colors.white70
)),
SizedBox(height: 4.h),
Text(_duration, style: TextStyle(
fontSize: 32.sp,
fontWeight: FontWeight.w700,
color: Colors.white
)),
],
),
);
}
紫色渐变是睡眠在整个App中的主题色,月亮图标强化了"睡眠"的概念。
睡眠时长会随着入睡/起床时间的修改实时更新,因为 _duration 是一个 getter,每次 build 都会重新计算。
时间选择卡片
入睡时间和起床时间用两个并排的卡片展示,点击可以修改。
Widget _buildTimeCards() {
return Row(
children: [
Expanded(child: _buildTimeCard('入睡时间', _bedTime, Icons.bedtime_outlined, () async {
final t = await showTimePicker(context: context, initialTime: _bedTime);
if (t != null) setState(() => _bedTime = t);
})),
SizedBox(width: 12.w),
Expanded(child: _buildTimeCard('起床时间', _wakeTime, Icons.wb_sunny_outlined, () async {
final t = await showTimePicker(context: context, initialTime: _wakeTime);
if (t != null) setState(() => _wakeTime = t);
})),
],
);
}
showTimePicker 是 Flutter 内置的时间选择器,会弹出一个圆盘式的时间选择界面。返回值是 Future<TimeOfDay?>,用户取消选择时返回 null。
两个卡片用 Expanded 平分宽度,中间留 12 像素间距。
单个时间卡片
抽取一个可复用的时间卡片组件。
Widget _buildTimeCard(String label, TimeOfDay time, IconData icon, VoidCallback onTap) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r)
),
child: Column(
children: [
Icon(icon, size: 24.w, color: const Color(0xFF845EC2)),
SizedBox(height: 8.h),
Text(label, style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[500]
)),
SizedBox(height: 4.h),
Text(time.format(context), style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.w600,
color: const Color(0xFF1A1A2E)
)),
],
),
),
);
}
入睡用床铺图标 bedtime_outlined,起床用太阳图标 wb_sunny_outlined,直观表达含义。
time.format(context) 会根据系统设置显示 12 小时制或 24 小时制。
睡眠质量评分
用表情符号让用户评价睡眠质量,比数字评分更直观。
Widget _buildQualityCard() {
final qualities = ['很差', '较差', '一般', '良好', '很好'];
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('睡眠质量', style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: const Color(0xFF1A1A2E)
)),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(5, (i) {
final isSelected = _quality == i;
return GestureDetector(
onTap: () => setState(() => _quality = i),
child: Column(
children: [
Container(
width: 48.w,
height: 48.w,
decoration: BoxDecoration(
color: isSelected ? const Color(0xFF845EC2) : Colors.grey[100],
borderRadius: BorderRadius.circular(14.r),
),
child: Center(
child: Text(
['😫', '😕', '😐', '🙂', '😊'][i],
style: TextStyle(fontSize: 22.sp)
)
),
),
SizedBox(height: 6.h),
Text(qualities[i], style: TextStyle(
fontSize: 11.sp,
color: isSelected ? const Color(0xFF845EC2) : Colors.grey[500]
)),
],
),
);
}),
),
],
),
);
}
}
5 个表情从左到右表示从差到好:😫😕😐🙂😊。选中的表情背景变成紫色,文字也变成紫色。
用 List.generate(5, (i) => ...) 生成 5 个评分选项,比手写 5 个 Widget 更简洁。
睡眠数据分析
有了入睡时间、起床时间和质量评分,可以做很多分析:
- 平均睡眠时长
- 入睡时间规律性
- 睡眠质量趋势
- 睡眠不足预警
这些功能可以在统计页面实现。
睡眠建议
根据睡眠数据给出建议:
String get _suggestion {
final hours = (_wakeTime.hour * 60 + _wakeTime.minute -
_bedTime.hour * 60 - _bedTime.minute + 24 * 60) % (24 * 60) / 60;
if (hours < 6) return '睡眠时间不足,建议增加睡眠';
if (hours > 9) return '睡眠时间过长,可能影响精神状态';
if (_bedTime.hour >= 0 && _bedTime.hour < 22) return '入睡时间较早';
if (_bedTime.hour >= 1 && _bedTime.hour < 6) return '熬夜对身体不好哦';
return '作息规律,继续保持';
}
这种个性化建议能增加用户粘性。
小结
睡眠记录页面的特点:
- 自动计算睡眠时长
- 时间选择器修改入睡/起床时间
- 表情评分评价睡眠质量
- 紫色主题色,和App中其他睡眠相关内容一致
表情评分是一个很好的交互设计,比 1-5 分的数字评分更有趣,用户更愿意参与。
下一篇会讲添加运动记录页面,运动需要选择类型和时长,还会计算消耗的卡路里。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)