flutter_for_openharmony口腔护理app实战+检查记录实现
本文介绍了如何在Flutter应用中实现口腔检查记录功能。该功能采用卡片式布局展示检查记录,包含检查类型、日期、医院、医生、结果、问题和建议等详细信息。页面结构包含标题栏、浮动添加按钮和记录列表,使用Consumer监听数据变化。每条记录以靛蓝色医疗服务图标为标识,通过分割线区分基本信息与详细内容。文章还提供了信息行组件的封装方法,以及添加记录对话框和数据模型的基本结构。该实现注重信息的清晰展示和

前言
定期的口腔检查是预防和早期发现口腔疾病的重要手段。在口腔护理应用中,记录每次检查的详细信息,包括检查类型、医院、医生、检查结果和建议等,可以帮助用户追踪自己的口腔健康状况,也便于在复诊时提供参考。
本文将介绍如何在 Flutter 中实现一个信息丰富的检查记录功能。
功能规划
检查记录页面需要实现以下功能:
- 记录列表:展示所有检查记录
- 详细信息:包括检查类型、日期、医院、医生、结果、问题、建议等
- 卡片布局:使用卡片形式展示每条记录的完整信息
- 添加记录:支持添加新的检查记录
页面基础结构
检查记录页面使用 StatelessWidget 实现:
class OralCheckPage extends StatelessWidget {
const OralCheckPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('检查记录')),
floatingActionButton: FloatingActionButton(
onPressed: () => _showAddDialog(context),
backgroundColor: const Color(0xFF26A69A),
child: const Icon(Icons.add),
),
页面结构与其他记录页面保持一致,包含标题栏和浮动操作按钮。
记录列表构建
使用 Consumer 监听数据变化:
body: Consumer<AppProvider>(
builder: (context, provider, _) {
if (provider.checkRecords.isEmpty) {
return const Center(child: Text('暂无检查记录'));
}
return ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: provider.checkRecords.length,
itemBuilder: (context, index) {
final record = provider.checkRecords[index];
标准的空状态检查和列表构建模式。
检查记录卡片
检查记录包含较多信息,使用卡片形式展示:
return Container(
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: const Color(0xFF5C6BC0).withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(Icons.medical_services,
color: Color(0xFF5C6BC0)),
),
检查记录使用靛蓝色作为主色调,医疗服务图标直观地表示检查这一行为。
卡片头部展示检查类型和日期:
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(record.checkType,
style: const TextStyle(fontWeight: FontWeight.bold,
fontSize: 16)),
Text(DateFormat('yyyy-MM-dd').format(record.date),
style: TextStyle(color: Colors.grey.shade600)),
],
),
),
],
),
检查类型作为主标题,日期作为副标题,形成清晰的信息层次。
分割线和详细信息区域:
const SizedBox(height: 12),
const Divider(height: 1),
const SizedBox(height: 12),
_buildInfoRow('医院', record.hospital ?? '未填写'),
_buildInfoRow('医生', record.doctorName ?? '未填写'),
_buildInfoRow('结果', record.result),
if (record.issues.isNotEmpty)
_buildInfoRow('问题', record.issues.join('、')),
if (record.advice != null)
_buildInfoRow('建议', record.advice!),
],
),
);
},
);
},
),
);
}
使用分割线将头部和详细信息分开。条件渲染确保只有存在数据时才显示对应字段。
信息行组件
封装信息行组件用于展示键值对:
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 50,
child: Text('$label:', style: TextStyle(color: Colors.grey.shade600)),
),
Expanded(child: Text(value)),
],
),
);
}
标签使用固定宽度,值使用 Expanded 占据剩余空间。crossAxisAlignment.start 确保多行文本时对齐顶部。
添加记录对话框
添加检查记录的对话框(简化版):
void _showAddDialog(BuildContext context) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('添加检查记录功能开发中')),
);
}
实际项目中需要实现完整的表单对话框。
数据模型定义
检查记录的数据模型:
class CheckRecord {
final String id;
final DateTime date;
final String checkType;
final String? hospital;
final String? doctorName;
final String result;
final List<String> issues;
final String? advice;
CheckRecord({
String? id,
required this.date,
required this.checkType,
this.hospital,
this.doctorName,
required this.result,
this.issues = const [],
this.advice,
}) : id = id ?? DateTime.now().millisecondsSinceEpoch.toString();
}
模型包含日期、检查类型、医院、医生、结果、问题列表和建议等字段。问题使用列表存储,支持记录多个问题。
Provider 数据管理
在 AppProvider 中管理检查记录:
List<CheckRecord> _checkRecords = [];
List<CheckRecord> get checkRecords => _checkRecords;
void addCheckRecord(CheckRecord record) {
_checkRecords.insert(0, record);
notifyListeners();
}
与其他记录类型保持一致的数据管理模式。
测试数据生成
生成测试数据:
void initTestData() {
_checkRecords = [
CheckRecord(
date: DateTime.now().subtract(const Duration(days: 30)),
checkType: '常规检查',
hospital: '市口腔医院',
doctorName: '张医生',
result: '整体健康',
issues: ['轻微牙结石'],
advice: '建议半年后洗牙',
),
CheckRecord(
date: DateTime.now().subtract(const Duration(days: 180)),
checkType: '洗牙',
hospital: '市口腔医院',
doctorName: '李医生',
result: '清洁完成',
advice: '注意日常刷牙方式',
),
];
}
测试数据包含不同类型的检查记录,便于验证显示效果。
完整添加对话框实现
实现完整的添加检查记录对话框:
void _showAddDialog(BuildContext context) {
final typeController = TextEditingController();
final hospitalController = TextEditingController();
final doctorController = TextEditingController();
final resultController = TextEditingController();
final adviceController = TextEditingController();
DateTime selectedDate = DateTime.now();
showDialog(
context: context,
builder: (ctx) => StatefulBuilder(
builder: (context, setState) => AlertDialog(
title: const Text('添加检查记录'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButtonFormField<String>(
decoration: const InputDecoration(labelText: '检查类型'),
items: const [
DropdownMenuItem(value: '常规检查', child: Text('常规检查')),
DropdownMenuItem(value: '洗牙', child: Text('洗牙')),
DropdownMenuItem(value: '补牙', child: Text('补牙')),
DropdownMenuItem(value: '拔牙', child: Text('拔牙')),
DropdownMenuItem(value: '其他', child: Text('其他')),
],
onChanged: (v) => typeController.text = v ?? '',
),
const SizedBox(height: 12),
TextField(
controller: hospitalController,
decoration: const InputDecoration(labelText: '医院'),
),
const SizedBox(height: 12),
TextField(
controller: doctorController,
decoration: const InputDecoration(labelText: '医生'),
),
const SizedBox(height: 12),
TextField(
controller: resultController,
decoration: const InputDecoration(labelText: '检查结果'),
maxLines: 2,
),
const SizedBox(height: 12),
TextField(
controller: adviceController,
decoration: const InputDecoration(labelText: '医生建议'),
maxLines: 2,
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('取消'),
),
ElevatedButton(
onPressed: () {
if (typeController.text.isEmpty || resultController.text.isEmpty) {
return;
}
final record = CheckRecord(
date: selectedDate,
checkType: typeController.text,
hospital: hospitalController.text.isEmpty
? null : hospitalController.text,
doctorName: doctorController.text.isEmpty
? null : doctorController.text,
result: resultController.text,
advice: adviceController.text.isEmpty
? null : adviceController.text,
);
context.read<AppProvider>().addCheckRecord(record);
Navigator.pop(ctx);
},
child: const Text('保存'),
),
],
),
),
);
}
表单包含检查类型下拉选择、医院、医生、结果和建议等输入字段。
检查类型图标映射
可以为不同检查类型使用不同图标:
IconData _getCheckTypeIcon(String type) {
switch (type) {
case '常规检查':
return Icons.search;
case '洗牙':
return Icons.cleaning_services;
case '补牙':
return Icons.build;
case '拔牙':
return Icons.remove_circle;
default:
return Icons.medical_services;
}
}
不同图标帮助用户快速识别检查类型。
检查提醒功能
可以根据上次检查时间提醒用户:
String getCheckReminder() {
if (_checkRecords.isEmpty) {
return '您还没有检查记录,建议每半年进行一次口腔检查';
}
final lastCheck = _checkRecords.first.date;
final daysSince = DateTime.now().difference(lastCheck).inDays;
if (daysSince > 180) {
return '距离上次检查已超过6个月,建议尽快预约检查';
} else if (daysSince > 150) {
return '距离上次检查已${daysSince}天,建议近期安排检查';
} else {
return '上次检查在${daysSince}天前,继续保持定期检查的好习惯';
}
}
根据检查间隔给出个性化提醒。
检查统计信息
统计检查相关数据:
Map<String, int> getCheckStats() {
final stats = <String, int>{};
for (var record in _checkRecords) {
stats[record.checkType] = (stats[record.checkType] ?? 0) + 1;
}
return stats;
}
int get totalCheckCount => _checkRecords.length;
int get thisYearCheckCount {
final thisYear = DateTime.now().year;
return _checkRecords.where((r) => r.date.year == thisYear).length;
}
统计各类型检查次数和年度检查次数。
页面顶部提醒卡片
在列表上方添加检查提醒:
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: const Color(0xFF5C6BC0).withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
const Icon(Icons.info_outline, color: Color(0xFF5C6BC0)),
const SizedBox(width: 12),
Expanded(
child: Text(
getCheckReminder(),
style: const TextStyle(color: Color(0xFF5C6BC0)),
),
),
],
),
)
提醒卡片使用主题色背景,突出显示检查建议。
问题标签展示
将问题列表以标签形式展示:
if (record.issues.isNotEmpty)
Wrap(
spacing: 8,
runSpacing: 4,
children: record.issues.map((issue) => Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(issue,
style: const TextStyle(color: Colors.orange, fontSize: 12)),
)).toList(),
),
使用 Wrap 组件让标签自动换行,橙色标签突出显示问题。
检查记录详情页
可以添加详情页展示更多信息:
void _showDetailPage(BuildContext context, CheckRecord record) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CheckDetailPage(record: record),
),
);
}
详情页可以展示完整的检查报告和历史对比。
数据导出功能
支持导出检查记录:
String exportCheckRecords() {
final buffer = StringBuffer();
buffer.writeln('口腔检查记录');
buffer.writeln('导出时间:${DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now())}');
buffer.writeln('');
for (var record in _checkRecords) {
buffer.writeln('检查类型:${record.checkType}');
buffer.writeln('检查日期:${DateFormat('yyyy-MM-dd').format(record.date)}');
buffer.writeln('医院:${record.hospital ?? '未填写'}');
buffer.writeln('医生:${record.doctorName ?? '未填写'}');
buffer.writeln('结果:${record.result}');
if (record.issues.isNotEmpty) {
buffer.writeln('问题:${record.issues.join('、')}');
}
if (record.advice != null) {
buffer.writeln('建议:${record.advice}');
}
buffer.writeln('---');
}
return buffer.toString();
}
导出功能便于用户保存或分享检查记录。
空状态优化
为空状态添加引导:
if (provider.checkRecords.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.medical_services, size: 64, color: Colors.grey.shade300),
const SizedBox(height: 16),
Text('暂无检查记录', style: TextStyle(color: Colors.grey.shade500)),
const SizedBox(height: 8),
Text('建议每半年进行一次口腔检查',
style: TextStyle(color: Colors.grey.shade400, fontSize: 12)),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: () => _showAddDialog(context),
icon: const Icon(Icons.add),
label: const Text('添加检查记录'),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF5C6BC0),
),
),
],
),
);
}
空状态页面添加健康提示和添加按钮。
总结
本文详细介绍了口腔护理 App 中检查记录功能的实现。通过卡片式布局和丰富的信息展示,我们构建了一个实用的检查记录管理页面。核心技术点包括:
- 使用卡片布局展示多字段信息
- 封装信息行组件提高代码复用
- 条件渲染处理可选字段
- 使用列表存储多个问题
检查记录功能帮助用户追踪口腔健康状况,是口腔护理应用的重要组成部分。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)