Flutter日程提醒插件remind_timetable的使用
Flutter日程提醒插件remind_timetable的使用
remind_timetable
是一个用于在 Flutter 应用程序中实现日程提醒功能的插件。它允许用户查看和管理时间表上的事件。本文将通过一个完整的示例来展示如何使用 remind_timetable
插件。
示例代码
import 'package:black_hole_flutter/black_hole_flutter.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:remind_timetable/timetable.dart';
import 'package:time/time.dart';
// 忽略未使用的导入
import 'positioning_demo.dart';
import 'utils.dart';
Future<void> main() async {
initDebugOverlay();
runApp(ExampleApp(child: TimetableExample()));
}
class TimetableExample extends StatefulWidget {
@override
State<TimetableExample> createState() => _TimetableExampleState();
}
// 定义一个全局键,用于获取 MultiDateContentGeometry 的状态
final GlobalKey<MultiDateContentGeometry> timetableKey = GlobalKey();
class _TimetableExampleState extends State<TimetableExample> with TickerProviderStateMixin {
// 设置初始可见日期范围
var _visibleDateRange = PredefinedVisibleDateRange.threeDays;
// 更新可见日期范围的方法
void _updateVisibleDateRange(PredefinedVisibleDateRange newValue) {
setState(() {
_visibleDateRange = newValue;
_dateController.visibleRange = newValue.visibleDateRange;
});
}
// 判断是否为固定布局
bool get _isRecurringLayout => _visibleDateRange == PredefinedVisibleDateRange.fixed;
// 初始化日期控制器
late final _dateController = DateController(
visibleRange: _visibleDateRange.visibleDateRange,
);
// 初始化时间控制器
final _timeController = TimeController(
maxRange: TimeRange(-3.hours, 26.hours),
);
// 存储拖拽事件
final _draggedEvents = <BasicEvent>[];
@override
void dispose() {
_timeController.dispose();
_dateController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TimetableConfig<BasicEvent>(
// 必需参数
dateController: _dateController,
timeController: _timeController,
eventBuilder: (context, event) => _buildPartDayEvent(event),
child: Column(children: [
Expanded(
child: _isRecurringLayout
? RecurringMultiDateTimetable<BasicEvent>()
: MultiDateTimetable<BasicEvent>(
headerBuilder: (context, leadingWidth) => ColoredBox(
color: Colors.amber.shade800.withOpacity(0.7),
child: MultiDateTimetableHeader<BasicEvent>(
leading: SizedBox(
width: leadingWidth,
child: Align(
heightFactor: 1,
alignment: Alignment.center,
child: WeekIndicator.forController(null),
),
),
),
),
contentBuilder: (context, onLeadingWidthChanged) => GestureDetector(
onTapDown: (details) {
final time = timetableKey.currentState!.resolveOffset(details.globalPosition);
print("Pointer at ${time} ${time.isUtc}");
},
child: MultiDateTimetableContent<BasicEvent>(
contentGeometryKey: timetableKey,
),
),
),
),
]),
// 可选参数
eventProvider: eventProviderFromFixedList(positioningDemoEvents),
allDayEventBuilder: (context, event, info) => BasicAllDayEventWidget(
event,
info: info,
onTap: () => _showSnackBar('All-day event $event tapped'),
),
timeOverlayProvider: mergeTimeOverlayProviders([
(context, date) => _draggedEvents
.map(
(it) => it.toTimeOverlay(context, date: date, widget: BasicEventWidget(it)),
)
.whereNotNull()
.toList(),
]),
callbacks: TimetableCallbacks(
onDateTap: (date) {
_showSnackBar('Tapped on date $date.');
_dateController.animateTo(date, vsync: this);
},
onDateBackgroundTap: (date) => _showSnackBar('Tapped on date background at $date.'),
onMultiDateHeaderOverflowTap: (date) => _showSnackBar('Tapped on the overflow of $date.'),
),
theme: TimetableThemeData(
context,
multiDateTimetableStyle: MultiDateTimetableStyle(context, contentBehindHead: true),
),
);
}
// 构建部分天数事件
Widget _buildPartDayEvent(BasicEvent event) {
final roundedTo = 15.minutes;
return PartDayDraggableEvent(
onDragStart: () => setState(() => _draggedEvents.add(event)),
onDragUpdate: (dateTime) => setState(() {
dateTime = dateTime.roundTimeToMultipleOf(roundedTo);
final index = _draggedEvents.indexWhere((it) => it.id == event.id);
final oldEvent = _draggedEvents[index];
_draggedEvents[index] = oldEvent.copyWith(
start: dateTime,
end: dateTime + oldEvent.duration,
);
}),
onDragEnd: (dateTime) {
dateTime = (dateTime ?? event.start).roundTimeToMultipleOf(roundedTo);
setState(() => _draggedEvents.removeWhere((it) => it.id == event.id));
_showSnackBar('Dragged event to $dateTime.');
},
onDragCanceled: (isMoved) => _showSnackBar('Your finger moved: $isMoved'),
child: BasicEventWidget(
event,
onTap: () => _showSnackBar('Part-day event $event tapped'),
),
);
}
// 构建应用栏
Widget _buildAppBar() {
final colorScheme = context.theme.colorScheme;
Widget child = AppBar(
elevation: 0,
titleTextStyle: TextStyle(color: colorScheme.onSurface),
iconTheme: IconThemeData(color: colorScheme.onSurface),
systemOverlayStyle: SystemUiOverlayStyle.light,
backgroundColor: Colors.transparent,
title: _isRecurringLayout ? null : MonthIndicator.forController(_dateController),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.today),
onPressed: () {
_dateController.animateToToday(vsync: this);
_timeController.animateToShowFullDay(vsync: this);
},
tooltip: 'Go to today',
),
const SizedBox(width: 8),
DropdownButton<PredefinedVisibleDateRange>(
onChanged: (visibleRange) => _updateVisibleDateRange(visibleRange!),
value: _visibleDateRange,
items: [
for (final visibleRange in PredefinedVisibleDateRange.values)
DropdownMenuItem(
value: visibleRange,
child: Text(visibleRange.title),
),
],
),
const SizedBox(width: 16),
],
);
if (!_isRecurringLayout) {
child = Column(children: [
child,
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Builder(builder: (context) {
return DefaultTimetableCallbacks(
callbacks: DefaultTimetableCallbacks.of(context)!.copyWith(
onDateTap: (date) {
_showSnackBar('Tapped on date $date.');
_updateVisibleDateRange(PredefinedVisibleDateRange.day);
_dateController.animateTo(date, vsync: this);
},
),
child: CompactMonthTimetable(),
);
}),
),
]);
}
return Material(color: colorScheme.surface, elevation: 4, child: child);
}
// 显示 SnackBar
void _showSnackBar(String content) => context.scaffoldMessenger.showSnackBar(SnackBar(content: Text(content)));
}
// 预定义的可见日期范围枚举
enum PredefinedVisibleDateRange { day, threeDays, workWeek, week, fixed }
// 枚举扩展方法
extension on PredefinedVisibleDateRange {
VisibleDateRange get visibleDateRange {
switch (this) {
case PredefinedVisibleDateRange.day:
return VisibleDateRange.days(1);
case PredefinedVisibleDateRange.threeDays:
return VisibleDateRange.days(3);
case PredefinedVisibleDateRange.workWeek:
return VisibleDateRange.weekAligned(5);
case PredefinedVisibleDateRange.week:
return VisibleDateRange.week();
case PredefinedVisibleDateRange.fixed:
return VisibleDateRange.fixed(
DateTimeTimetable.today(),
DateTime.daysPerWeek,
);
}
}
String get title {
switch (this) {
case PredefinedVisibleDateRange.day:
return 'Day';
case PredefinedVisibleDateRange.threeDays:
return '3 Days';
case PredefinedVisibleDateRange.workWeek:
return 'Work Week';
case PredefinedVisibleDateRange.week:
return 'Week';
case PredefinedVisibleDateRange.fixed:
return '7 Days (fixed)';
}
}
}
代码解释
主函数
Future<void> main() async {
initDebugOverlay();
runApp(ExampleApp(child: TimetableExample()));
}
- 初始化调试覆盖层。
- 运行应用程序,并传递
TimetableExample
组件作为子组件。
定义状态类
class TimetableExample extends StatefulWidget {
@override
State<TimetableExample> createState() => _TimetableExampleState();
}
- 创建一个
TimetableExample
状态类,用于管理状态。
初始化控件
final GlobalKey<MultiDateContentGeometry> timetableKey = GlobalKey();
class _TimetableExampleState extends State<TimetableExample> with TickerProviderStateMixin {
var _visibleDateRange = PredefinedVisibleDateRange.threeDays;
void _updateVisibleDateRange(PredefinedVisibleDateRange newValue) {
setState(() {
_visibleDateRange = newValue;
_dateController.visibleRange = newValue.visibleDateRange;
});
}
bool get _isRecurringLayout => _visibleDateRange == PredefinedVisibleDateRange.fixed;
late final _dateController = DateController(
visibleRange: _visibleDateRange.visibleDateRange,
);
final _timeController = TimeController(
maxRange: TimeRange(-3.hours, 26.hours),
);
final _draggedEvents = <BasicEvent>[];
- 定义全局键
timetableKey
用于获取MultiDateContentGeometry
的状态。 - 初始化
_visibleDateRange
为PredefinedVisibleDateRange.threeDays
。 - 定义
_updateVisibleDateRange
方法更新可见日期范围。 - 判断是否为固定布局。
- 初始化日期控制器
_dateController
和时间控制器_timeController
。 - 定义
_draggedEvents
存储拖拽事件。
处理生命周期
@override
void dispose() {
_timeController.dispose();
_dateController.dispose();
super.dispose();
}
- 在组件销毁时释放
_timeController
和_dateController
。
构建界面
@override
Widget build(BuildContext context) {
return TimetableConfig<BasicEvent>(
dateController: _dateController,
timeController: _timeController,
eventBuilder: (context, event) => _buildPartDayEvent(event),
child: Column(children: [
Expanded(
child: _isRecurringLayout
? RecurringMultiDateTimetable<BasicEvent>()
: MultiDateTimetable<BasicEvent>(
headerBuilder: (context, leadingWidth) => ColoredBox(
color: Colors.amber.shade800.withOpacity(0.7),
child: MultiDateTimetableHeader<BasicEvent>(
leading: SizedBox(
width: leadingWidth,
child: Align(
heightFactor: 1,
alignment: Alignment.center,
child: WeekIndicator.forController(null),
),
),
),
),
contentBuilder: (context, onLeadingWidthChanged) => GestureDetector(
onTapDown: (details) {
final time = timetableKey.currentState!.resolveOffset(details.globalPosition);
print("Pointer at ${time} ${time.isUtc}");
},
child: MultiDateTimetableContent<BasicEvent>(
contentGeometryKey: timetableKey,
),
),
),
),
]),
eventProvider: eventProviderFromFixedList(positioningDemoEvents),
allDayEventBuilder: (context, event, info) => BasicAllDayEventWidget(
event,
info: info,
onTap: () => _showSnackBar('All-day event $event tapped'),
),
timeOverlayProvider: mergeTimeOverlayProviders([
(context, date) => _draggedEvents
.map(
(it) => it.toTimeOverlay(context, date: date, widget: BasicEventWidget(it)),
)
.whereNotNull()
.toList(),
]),
callbacks: TimetableCallbacks(
onDateTap: (date) {
_showSnackBar('Tapped on date $date.');
_dateController.animateTo(date, vsync: this);
},
onDateBackgroundTap: (date) => _showSnackBar('Tapped on date background at $date.'),
onMultiDateHeaderOverflowTap: (date) => _showSnackBar('Tapped on the overflow of $date.'),
),
theme: TimetableThemeData(
context,
multiDateTimetableStyle: MultiDateTimetableStyle(context, contentBehindHead: true),
),
);
}
- 使用
TimetableConfig
组件构建时间表配置。 - 设置必需的参数,如日期控制器、时间控制器和事件构建器。
- 设置可选参数,如事件提供器、全天事件构建器、时间覆盖提供器和回调。
- 设置主题样式。
构建部分天数事件
Widget _buildPartDayEvent(BasicEvent event) {
final roundedTo = 15.minutes;
return PartDayDraggableEvent(
onDragStart: () => setState(() => _draggedEvents.add(event)),
onDragUpdate: (dateTime) => setState(() {
dateTime = dateTime.roundTimeToMultipleOf(roundedTo);
final index = _draggedEvents.indexWhere((it) => it.id == event.id);
final oldEvent = _draggedEvents[index];
_draggedEvents[index] = oldEvent.copyWith(
start: dateTime,
end: dateTime + oldEvent.duration,
);
}),
onDragEnd: (dateTime) {
dateTime = (dateTime ?? event.start).roundTimeToMultipleOf(roundedTo);
setState(() => _draggedEvents.removeWhere((it) => it.id == event.id));
_showSnackBar('Dragged event to $dateTime.');
},
onDragCanceled: (isMoved) => _showSnackBar('Your finger moved: $isMoved'),
child: BasicEventWidget(
event,
onTap: () => _showSnackBar('Part-day event $event tapped'),
),
);
}
- 构建部分天数事件。
- 设置拖拽事件的开始、更新和结束逻辑。
- 设置拖拽取消事件的逻辑。
构建应用栏
Widget _buildAppBar() {
final colorScheme = context.theme.colorScheme;
Widget child = AppBar(
elevation: 0,
titleTextStyle: TextStyle(color: colorScheme.onSurface),
iconTheme: IconThemeData(color: colorScheme.onSurface),
systemOverlayStyle: SystemUiOverlayStyle.light,
backgroundColor: Colors.transparent,
title: _isRecurringLayout ? null : MonthIndicator.forController(_dateController),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.today),
onPressed: () {
_dateController.animateToToday(vsync: this);
_timeController.animateToShowFullDay(vsync: this);
},
tooltip: 'Go to today',
),
const SizedBox(width: 8),
DropdownButton<PredefinedVisibleDateRange>(
onChanged: (visibleRange) => _updateVisibleDateRange(visibleRange!),
value: _visibleDateRange,
items: [
for (final visibleRange in PredefinedVisibleDateRange.values)
DropdownMenuItem(
value: visibleRange,
child: Text(visibleRange.title),
),
],
),
const SizedBox(width: 16),
],
);
if (!_isRecurringLayout) {
child = Column(children: [
child,
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Builder(builder: (context) {
return DefaultTimetableCallbacks(
callbacks: DefaultTimetableCallbacks.of(context)!.copyWith(
onDateTap: (date) {
_showSnackBar('Tapped on date $date.');
_updateVisibleDateRange(PredefinedVisibleDateRange.day);
_dateController.animateTo(date, vsync: this);
},
),
child: CompactMonthTimetable(),
);
}),
),
]);
}
return Material(color: colorScheme.surface, elevation: 4, child: child);
}
- 构建应用栏。
- 设置应用栏的属性,如背景颜色、图标等。
- 添加按钮和下拉菜单,用于切换日期范围。
显示 SnackBar
void _showSnackBar(String content) => context.scaffoldMessenger.showSnackBar(SnackBar(content: Text(content)));
- 显示
SnackBar
以提示用户操作结果。
预定义的可见日期范围枚举
enum PredefinedVisibleDateRange { day, threeDays, workWeek, week, fixed }
- 定义预定义的可见日期范围枚举。
枚举扩展方法
extension on PredefinedVisibleDateRange {
VisibleDateRange get visibleDateRange {
switch (this) {
case PredefinedVisibleDateRange.day:
return VisibleDateRange.days(1);
case PredefinedVisibleDateRange.threeDays:
return VisibleDateRange.days(3);
case PredefinedVisibleDateRange.workWeek:
return VisibleDateRange.weekAligned(5);
case PredefinedVisibleDateRange.week:
return VisibleDateRange.week();
case PredefinedVisibleDateRange.fixed:
return VisibleDateRange.fixed(
DateTimeTimetable.today(),
DateTime.daysPerWeek,
);
}
}
String get title {
switch (this) {
case PredefinedVisibleDateRange.day:
return 'Day';
case PredefinedVisibleDateRange.threeDays:
return '3 Days';
case PredefinedVisibleDateRange.workWeek:
return 'Work Week';
case PredefinedVisibleDateRange.week:
return 'Week';
case PredefinedVisibleDateRange.fixed:
return '7 Days (fixed)';
}
}
}
更多关于Flutter日程提醒插件remind_timetable的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter日程提醒插件remind_timetable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
remind_timetable
是一个 Flutter 插件,用于在应用程序中实现日程提醒功能。虽然这个插件的具体实现可能会有所不同,但通常情况下,它会提供一些基本的功能,如添加、删除、更新和查看日程提醒。
以下是一个基本的使用指南,假设你已经创建了一个 Flutter 项目并添加了 remind_timetable
插件到你的 pubspec.yaml
文件中。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 remind_timetable
插件的依赖:
dependencies:
flutter:
sdk: flutter
remind_timetable: ^latest_version
然后运行 flutter pub get
来获取依赖。
2. 导入插件
在你的 Dart 文件中导入 remind_timetable
插件:
import 'package:remind_timetable/remind_timetable.dart';
3. 初始化插件
在使用插件之前,通常需要初始化它。你可以通过调用 RemindTimetable.initialize()
来完成初始化:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await RemindTimetable.initialize();
runApp(MyApp());
}
4. 添加日程提醒
你可以使用 RemindTimetable.addReminder()
方法来添加一个新的日程提醒。通常,你需要提供提醒的标题、描述、时间等信息。
void addReminder() async {
Reminder reminder = Reminder(
title: 'Meeting with Team',
description: 'Discuss project updates',
time: DateTime.now().add(Duration(hours: 1)),
);
await RemindTimetable.addReminder(reminder);
}
5. 获取日程提醒
你可以使用 RemindTimetable.getReminders()
方法来获取所有的日程提醒:
void getReminders() async {
List<Reminder> reminders = await RemindTimetable.getReminders();
for (var reminder in reminders) {
print('Title: ${reminder.title}, Time: ${reminder.time}');
}
}
6. 更新日程提醒
你可以使用 RemindTimetable.updateReminder()
方法来更新现有的日程提醒:
void updateReminder(Reminder reminder) async {
reminder.title = 'Updated Meeting Title';
await RemindTimetable.updateReminder(reminder);
}
7. 删除日程提醒
你可以使用 RemindTimetable.deleteReminder()
方法来删除一个日程提醒:
void deleteReminder(Reminder reminder) async {
await RemindTimetable.deleteReminder(reminder);
}
8. 监听提醒事件
有些插件可能支持监听提醒事件,例如提醒触发时执行某些操作:
void listenToReminders() {
RemindTimetable.onReminderTriggered.listen((Reminder reminder) {
print('Reminder triggered: ${reminder.title}');
});
}
9. 错误处理
在使用插件时,记得处理可能出现的异常:
void addReminder() async {
try {
Reminder reminder = Reminder(
title: 'Meeting with Team',
description: 'Discuss project updates',
time: DateTime.now().add(Duration(hours: 1)),
);
await RemindTimetable.addReminder(reminder);
} catch (e) {
print('Failed to add reminder: $e');
}
}
10. UI 集成
最后,将上述逻辑集成到你的 Flutter UI 中。例如,你可以在按钮的 onPressed
事件中调用 addReminder()
方法:
ElevatedButton(
onPressed: addReminder,
child: Text('Add Reminder'),
);