用药提醒列表是帮助用户管理所有提醒的中心页面。用户可以查看所有提醒的状态,通过开关快速启用或停用提醒,还可以查看历史记录。
功能设计思路
提醒列表展示所有用药提醒,每个提醒卡片包含药品名称、服药人、用量、提醒时间和状态开关。使用不同颜色区分启用和停用状态,提供直观的视觉反馈。
页面结构实现
列表页面使用StatelessWidget:
dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('用药提醒'),
actions: [
IconButton(
icon: const Icon(Icons.history),
onPressed: () => Get.to(() => const ReminderHistoryScreen()),
),
],
),
body: Consumer<ReminderProvider>(
builder: (context, provider, child) {
final reminders = provider.reminders;
if (reminders.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.alarm_off, size: 64.sp, color: Colors.grey[300]),
SizedBox(height: 16.h),
Text('暂无用药提醒', style: TextStyle(color: Colors.grey[500], fontSize: 16.sp)),
SizedBox(height: 16.h),
ElevatedButton(
onPressed: () => Get.to(() => const AddReminderScreen()),
child: const Text('添加提醒'),
),
],
),
);
}
return ListView.builder(
padding: EdgeInsets.all(16.w),
itemCount: reminders.length,
itemBuilder: (context, index) {
final reminder = reminders[index];
return _buildReminderCard(context, reminder, provider);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => Get.to(() => const AddReminderScreen()),
backgroundColor: const Color(0xFF00897B),
child: const Icon(Icons.add),
),
);
}
AppBar右侧提供历史记录入口,让用户可以查看过往的服药记录。使用Consumer监听Provider,当提醒数据变化时自动更新列表。
提醒卡片设计
每个提醒卡片分为两部分:
dart
Widget _buildReminderCard(BuildContext context, dynamic reminder, ReminderProvider provider) {
return Container(
margin: EdgeInsets.only(bottom: 12.h),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2)),
],
),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(12.w),
child: Row(
children: [
Container(
width: 48.w,
height: 48.w,
decoration: BoxDecoration(
color: reminder.isActive
? const Color(0xFF00897B).withOpacity(0.1)
: Colors.grey.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
),
child: Icon(
Icons.medication,
color: reminder.isActive ? const Color(0xFF00897B) : Colors.grey,
),
),
SizedBox(width: 12.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
reminder.medicineName,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: reminder.isActive ? Colors.black : Colors.grey,
),
),
SizedBox(height: 4.h),
Text(
'${reminder.memberName} · ${reminder.dosage}',
style: TextStyle(fontSize: 12.sp, color: Colors.grey[600]),
),
],
),
),
Switch(
value: reminder.isActive,
onChanged: (value) {
provider.toggleReminderActive(reminder.id);
},
activeColor: const Color(0xFF00897B),
),
],
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.grey[50],
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12.r),
bottomRight: Radius.circular(12.r),
),
),
child: Row(
children: [
Icon(Icons.access_time, size: 16.sp, color: Colors.grey[600]),
SizedBox(width: 4.w),
Expanded(
child: Text(
reminder.reminderTimes
.map((t) => DateFormat('HH:mm').format(t))
.join(' · '),
style: TextStyle(fontSize: 12.sp, color: Colors.grey[600]),
),
),
Text(
reminder.frequency,
style: TextStyle(fontSize: 12.sp, color: const Color(0xFF00897B)),
),
],
),
),
],
),
);
}
上半部分:显示药品图标、名称、服药人、用量和状态开关。图标和文字颜色根据启用状态动态变化,停用时使用灰色。
下半部分:显示提醒时间和频率。使用浅灰色背景区分,时间使用点号分隔,频率使用主题色突出显示。
状态开关
Switch组件控制提醒启用状态:
dart
Switch(
value: reminder.isActive,
onChanged: (value) {
provider.toggleReminderActive(reminder.id);
},
activeColor: const Color(0xFF00897B),
)
用户点击开关时,调用Provider的toggleReminderActive方法切换状态。Provider会通知所有监听者更新UI,卡片的颜色和文字会立即改变。
时间格式化
提醒时间使用DateFormat格式化:
dart
reminder.reminderTimes
.map((t) => DateFormat('HH:mm').format(t))
.join(' · ')
将DateTime列表转换为"HH:mm"格式的字符串,使用点号连接多个时间。这种格式清晰易读,用户一眼就能看出所有提醒时间。
Provider提醒管理
Provider提供提醒管理方法:
dart
class ReminderProvider extends ChangeNotifier {
final List<MedicineReminder> _reminders = [];
List<MedicineReminder> get reminders => _reminders;
void toggleReminderActive(String id) {
final index = _reminders.indexWhere((r) => r.id == id);
if (index != -1) {
_reminders[index] = _reminders[index].copyWith(
isActive: !_reminders[index].isActive,
);
notifyListeners();
}
}
void addReminder(MedicineReminder reminder) {
_reminders.add(reminder);
notifyListeners();
}
}
toggleReminderActive方法找到对应提醒,使用copyWith创建新对象并切换isActive状态。这种不可变数据的设计让状态管理更加可靠。
空状态设计
空状态提示包含图标、文字和添加按钮。使用闹钟关闭图标,暗示当前没有提醒。这种设计让空状态成为引导用户添加提醒的入口。
颜色语义化
启用状态使用主题色(青绿色),表示正常工作。停用状态使用灰色,表示暂停。这种颜色编码让用户能够快速识别提醒状态,无需阅读文字。
卡片分层设计
卡片分为上下两层,上层是主要信息,下层是时间详情。使用不同背景色区分,让信息层次更加清晰。这种设计在保持紧凑的同时,提供了完整的信息展示。
响应式更新
使用Consumer监听Provider,当提醒状态变化时,卡片会自动更新颜色和文字。比如用户关闭提醒后,图标和文字立即变为灰色,提供即时的视觉反馈。
提醒搜索功能
当提醒数量较多时,搜索功能帮助用户快速找到目标提醒:
dart
class _ReminderListScreenState extends State<ReminderListScreen> {
String _searchQuery = '';
final TextEditingController _searchController = TextEditingController();
List<MedicineReminder> _filterReminders(List<MedicineReminder> reminders) {
if (_searchQuery.isEmpty) return reminders;
return reminders.where((r) {
return r.medicineName.contains(_searchQuery) ||
r.memberName.contains(_searchQuery);
}).toList();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('用药提醒'),
bottom: PreferredSize(
preferredSize: Size.fromHeight(56.h),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
hintText: '搜索提醒...',
prefixIcon: const Icon(Icons.search),
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
borderSide: BorderSide.none,
),
),
onChanged: (v) => setState(() => _searchQuery = v),
),
),
),
),
body: Consumer<ReminderProvider>(
builder: (context, provider, child) {
final filtered = _filterReminders(provider.reminders);
return ListView.builder(
itemCount: filtered.length,
itemBuilder: (context, index) => _buildReminderCard(context, filtered[index], provider),
);
},
),
);
}
}
搜索框放置在AppBar的bottom区域,用户输入时实时过滤提醒列表。搜索范围包括药品名称和服药人姓名,方便用户通过不同方式查找提醒。
提醒分组显示
按启用状态分组显示提醒,让列表更加清晰:
dart
Widget _buildGroupedList(List<MedicineReminder> reminders) {
final activeReminders = reminders.where((r) => r.isActive).toList();
final inactiveReminders = reminders.where((r) => !r.isActive).toList();
return ListView(
padding: EdgeInsets.all(16.w),
children: [
if (activeReminders.isNotEmpty) ...[
_buildSectionHeader('启用中 (${activeReminders.length})'),
...activeReminders.map((r) => _buildReminderCard(context, r, provider)),
],
if (inactiveReminders.isNotEmpty) ...[
SizedBox(height: 16.h),
_buildSectionHeader('已停用 (${inactiveReminders.length})'),
...inactiveReminders.map((r) => _buildReminderCard(context, r, provider)),
],
],
);
}
Widget _buildSectionHeader(String title) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Text(
title,
style: TextStyle(fontSize: 14.sp, color: Colors.grey[600], fontWeight: FontWeight.w500),
),
);
}
提醒按启用状态分为两组,启用中的提醒显示在上方,已停用的显示在下方。每组都有标题显示数量,让用户一目了然。这种分组设计让提醒管理更加有序。
滑动删除功能
为提醒卡片添加滑动删除功能:
dart
Widget _buildDismissibleCard(MedicineReminder reminder, ReminderProvider provider) {
return Dismissible(
key: Key(reminder.id),
direction: DismissDirection.endToStart,
background: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20.w),
color: Colors.red,
child: const Icon(Icons.delete, color: Colors.white),
),
confirmDismiss: (direction) async {
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('确认删除'),
content: Text('确定要删除"${reminder.medicineName}"的提醒吗?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('取消'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('删除', style: TextStyle(color: Colors.red)),
),
],
),
);
},
onDismissed: (direction) {
provider.deleteReminder(reminder.id);
Get.snackbar('已删除', '提醒已删除', snackPosition: SnackPosition.BOTTOM);
},
child: _buildReminderCard(context, reminder, provider),
);
}
使用Dismissible组件包裹提醒卡片,支持从右向左滑动删除。删除前弹出确认对话框,防止误操作。删除后显示Snackbar提示,让用户知道操作已完成。
批量操作功能
提供批量启用/停用提醒的功能:
dart
bool _isSelectionMode = false;
Set<String> _selectedIds = {};
Widget _buildBatchActions() {
return Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, -2)),
],
),
child: Row(
children: [
Text('已选择 ${_selectedIds.length} 项', style: TextStyle(fontSize: 14.sp)),
const Spacer(),
TextButton(
onPressed: () => _batchToggle(true),
child: const Text('全部启用'),
),
TextButton(
onPressed: () => _batchToggle(false),
child: const Text('全部停用'),
),
TextButton(
onPressed: _batchDelete,
child: const Text('删除', style: TextStyle(color: Colors.red)),
),
],
),
);
}
void _batchToggle(bool active) {
final provider = context.read<ReminderProvider>();
for (final id in _selectedIds) {
provider.setReminderActive(id, active);
}
setState(() {
_isSelectionMode = false;
_selectedIds.clear();
});
}
长按提醒卡片进入选择模式,可以选择多个提醒进行批量操作。底部显示操作栏,提供全部启用、全部停用和删除三个选项。批量操作完成后自动退出选择模式。
提醒统计信息
在列表顶部显示提醒统计信息:
dart
Widget _buildStatistics(List<MedicineReminder> reminders) {
final totalCount = reminders.length;
final activeCount = reminders.where((r) => r.isActive).length;
final todayCount = reminders.where((r) {
final now = DateTime.now();
return r.reminderTimes.any((t) =>
t.hour >= now.hour || (t.hour == now.hour && t.minute >= now.minute));
}).length;
return Container(
margin: EdgeInsets.all(16.w),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: const Color(0xFF00897B).withOpacity(0.1),
borderRadius: BorderRadius.circular(12.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem('总提醒', totalCount.toString()),
_buildStatItem('启用中', activeCount.toString()),
_buildStatItem('今日待服', todayCount.toString()),
],
),
);
}
统计信息显示总提醒数、启用中的提醒数和今日待服药的提醒数。这些信息帮助用户快速了解提醒的整体情况。
提醒时间冲突检测
添加新提醒时检测时间冲突:
dart
bool _hasTimeConflict(MedicineReminder newReminder) {
final provider = context.read<ReminderProvider>();
final existingReminders = provider.reminders.where((r) =>
r.memberId == newReminder.memberId && r.isActive).toList();
for (final existing in existingReminders) {
for (final newTime in newReminder.reminderTimes) {
for (final existingTime in existing.reminderTimes) {
final diff = (newTime.hour * 60 + newTime.minute) -
(existingTime.hour * 60 + existingTime.minute);
if (diff.abs() < 30) {
return true;
}
}
}
}
return false;
}
检测同一成员的提醒时间是否间隔过近(小于30分钟)。如果存在冲突,提示用户调整时间,避免同时服用多种药物可能带来的风险。
总结
用药提醒列表通过卡片式设计和状态开关,让用户能够方便地管理所有提醒。颜色编码和分层布局提供了清晰的信息展示,Provider管理状态确保数据的响应式更新。搜索、分组、批量操作等功能让提醒管理更加高效便捷。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net