Flutter自定义日历插件flutter_customizable_calendar的使用

发布于 1周前 作者 yuanlaile 来自 Flutter

Flutter自定义日历插件flutter_customizable_calendar的使用

flutter_customizable_calendar 是一个功能丰富的Flutter包,提供高度可定制的日历视图,支持显示天、周和月。它允许开发者自定义日历的外观,并支持事件和休息时间的添加、动态编辑和删除。

主要特点

  • 多种视图:提供了三种主要视图:DaysViewWeekViewMonthViewScheduleListView,每种视图对应不同的时间段。
  • 自定义:用户可以通过不同的组件主题(如 DaysListThemeTimelineTheme 等)轻松自定义日历的外观。
  • 动态事件编辑:支持在每个视图中动态编辑事件,利用回调函数(如 onEventUpdatedonDiscardChanges)可以无缝更新或丢弃对事件所做的更改。
  • 事件类型:支持多种事件类型,包括 SimpleEventTaskDueBreak。可以创建自己的扩展相应抽象事件类的事件类型。
  • 动态添加事件:用户可以动态添加事件。示例代码展示了如何使用底部弹出框和 onDateLongPress 回调实现此功能。
  • 完整示例:该包附带了一个完整的示例应用程序,演示了其用法和特性。示例代码可以在GitHub上找到。

开始使用

添加依赖

首先,在 pubspec.yaml 文件中添加以下依赖:

dependencies:
  flutter_customizable_calendar: ^0.3.7

然后运行:

$ flutter pub get

使用示例

动态添加事件

下面的代码片段展示了如何处理 DaysView 中的日期长按事件并动态添加不同类型的事件,例如简单事件、任务到期和休息时间。

import 'package:flutter/material.dart';
import 'package:flutter_customizable_calendar/flutter_customizable_calendar.dart';

Future<CalendarEvent?> _onDateLongPress(DateTime timestamp) async {
  final _minute = timestamp.minute;
  return await showModalBottomSheet(
    context: context,
    builder: (context) => Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        const SizedBox(height: 32),
        ListTile(
          title: Text("Simple Event"),
          onTap: () {
            final SimpleEvent newItem = SimpleEvent(
              id: const Uuid().v1(),
              start: timestamp.subtract(Duration(minutes: _minute)),
              duration: Duration(hours: 1),
              title: "Simple event",
            );
            listCubit.save(newItem);
            Navigator.of(context).pop(newItem);
          },
        ),
        ListTile(
          title: Text("Task Due"),
          onTap: () {
            final TaskDue newItem = TaskDue(
              id: const Uuid().v1(),
              start: timestamp.subtract(Duration(minutes: _minute)),
            );
            listCubit.save(newItem);
            Navigator.of(context).pop(newItem);
          },
        ),
        ListTile(
          title: Text("Break"),
          onTap: () {
            final Break newItem = Break(
              id: const Uuid().v1(),
              start: timestamp.subtract(Duration(minutes: _minute)),
              duration: Duration(hours: 1),
            );
            listCubit.save(newItem);
            Navigator.of(context).pop(newItem);
          },
        ),
      ],
    ),
  );
}

DaysView<T>(
  //...
  onDateLongPress: _onDateLongPress,
)

WeekView<T>(
  //...
  onDateLongPress: _onDateLongPress,
)

MonthView<T>(
  //...
  onDateLongPress: _onDateLongPress,
)

动态编辑事件

通过利用提供的回调函数(如 onEventUpdatedonDiscardChanges),可以轻松地在日历视图中动态编辑事件。

void save(CalendarEvent event) {
  if (event is Break) {
    emit(state.copyWith(breaks: state.breaks..[event.id] = event));
  }
  if (event is FloatingCalendarEvent) {
    emit(state.copyWith(events: state.events..[event.id] = event));
  }
}

DaysView<T>(
    //...
    onEventUpdated: (obj) {
      print(obj);
      context.read<ListCubit>().save(obj);
    },
    onDiscardChanges: (obj) {
      print(obj);
    },
  )

WeekView<T>(
    //...
    onEventTap: print,
    onEventUpdated: (obj) {
      print(obj);
      context.read<ListCubit>().save(obj);
    },
    onDiscardChanges: (obj) {
      print(obj);
    },
  );

MonthView<T>(
    //...
    onEventTap: print,
    onEventUpdated: (obj) {
      print(obj);
      context.read<ListCubit>().save(obj);
    },
    onDiscardChanges: (obj) {
      print(obj);
    },
  );

全天事件

该包支持 DaysViewWeekView 的全天事件。以下代码片段展示了如何创建一个全天事件:

SimpleAllDayEvent(
  id: 'All-day 1',
  start: today,
  duration: const Duration(days: 2),
  title: 'Event 1',
  color: Colors.redAccent.shade200,
)

DaysView<T>(
  //...
  events: [
    SimpleAllDayEvent(
      id: 'All-day 1',
      start: today,
      duration: const Duration(days: 2),
      title: 'Event 1',
      color: Colors.redAccent.shade200,
    ),
  ],
)

WeekView<T>(
  //...
  events: [
    SimpleAllDayEvent(
      id: 'All-day 1',
      start: today,
      duration: const Duration(days: 2),
      title: 'Event 1',
      color: Colors.redAccent.shade200,
    ),
  ],
)

自定义事件

为了创建自定义事件,需要扩展 EditableCalendarEvent 类。以下代码片段展示了如何创建带有图像背景的自定义事件:

class EventWithLabel extends EditableCalendarEvent {
  EventWithLabel({
    required super.id,
    required super.start,
    required super.duration,
    required this.title,
    required this.label,
  });

  final String title;
  final EventLabel label;

  [@override](/user/override)
  EditableCalendarEvent copyWith({DateTime? start, Duration? duration}) {
    return EventWithLabel(
      id: id,
      start: start ?? this.start,
      duration: duration ?? this.duration,
      label: label,
      title: title,
    );
  }
}

Row _buildEventWithLabel(
  CalendarEvent data, {
  bool allDay = false,
}) {
  final event = data as EventWithLabel;

  return Row(
    children: [
      Container(
        width: 4,
        decoration: BoxDecoration(
          color: event.label.color,
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(4),
            bottomLeft: Radius.circular(4),
          ),
        ),
      ),
      Expanded(
        child: Container(
          height: double.maxFinite,
          decoration: BoxDecoration(
            color: event.label.color.withOpacity(0.25),
            borderRadius: BorderRadius.circular(allDay ? 2 : 4),
          ),
          padding: EdgeInsets.all(allDay ? 2 : 8),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: Text(
                  event.title,
                  style: const TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.w500,
                  ),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ],
          ),
        ),
      ),
    ],
  );
}

完整示例应用

以下是完整的示例应用,展示了如何使用 flutter_customizable_calendar 包的不同视图。

import 'package:flutter/material.dart';
import 'package:flutter_customizable_calendar/flutter_customizable_calendar.dart';

void main() => runApp(const App());

class App extends StatelessWidget {
  const App({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter customizable calendar',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        scaffoldBackgroundColor: Colors.blue.shade50,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter customizable calendar'),
      ),
      body: ListView(
        children: [
          ListTile(
            title: const Text('MonthView + ScheduleListView'),
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => MonthViewWithScheduleListViewPage()),
            ),
          ),
          ListTile(
            title: const Text("ScheduleListView + DaysView"),
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => ScheduleListViewWithDaysView()),
            ),
          ),
          ListTile(
            title: const Text("WeekView"),
            onTap: () => Navigator.of(context).push(
              MaterialPageRoute(builder: (context) => WeekViewPage()),
            ),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter自定义日历插件flutter_customizable_calendar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义日历插件flutter_customizable_calendar的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 flutter_customizable_calendar 插件的示例代码。这个插件允许你创建一个高度可定制的日历视图。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_customizable_calendar 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_customizable_calendar: ^x.y.z  # 请替换为最新版本号

然后运行 flutter pub get 来安装依赖。

接下来是一个简单的示例,展示如何使用 flutter_customizable_calendar 插件:

import 'package:flutter/material.dart';
import 'package:flutter_customizable_calendar/flutter_customizable_calendar.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Customizable Calendar Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: CalendarScreen(),
    );
  }
}

class CalendarScreen extends StatefulWidget {
  @override
  _CalendarScreenState createState() => _CalendarScreenState();
}

class _CalendarScreenState extends State<CalendarScreen> {
  final CalendarController _controller = CalendarController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Customizable Calendar'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: CustomizableCalendar(
          controller: _controller,
          firstDayOfWeek: DayOfWeek.monday,
          headerStyle: CalendarHeaderStyle(
            titleTextStyle: TextStyle(fontSize: 24, color: Colors.black),
            dayOfWeekTextStyle: TextStyle(fontSize: 16, color: Colors.grey),
          ),
          eventStyle: CalendarEventStyle(
            dotColor: Colors.blue,
            dotContainerDecoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Colors.white,
              border: Border.all(color: Colors.blue, width: 2),
            ),
          ),
          selectedDayStyle: CalendarSelectedDayStyle(
            backgroundColor: Colors.blue.withOpacity(0.3),
            textStyle: TextStyle(color: Colors.white, fontSize: 18),
          ),
          todayStyle: CalendarTodayStyle(
            backgroundColor: Colors.red.withOpacity(0.3),
            textStyle: TextStyle(color: Colors.white, fontSize: 18),
          ),
          calendarFormat: CalendarFormat.month,
          events: _getEvents(),
          onDaySelected: (date, events) {
            print('Selected date: $date, events: $events');
          },
          onTodayPressed: () {
            print('Today button pressed');
          },
          onVisibleDaysChanged: (firstVisible, lastVisible) {
            print('Visible days range changed: $firstVisible - $lastVisible');
          },
        ),
      ),
    );
  }

  List<CalendarEvent> _getEvents() {
    return [
      CalendarEvent(
        date: DateTime(2023, 10, 5),
        title: 'Event 1',
        description: 'This is the first event.',
      ),
      CalendarEvent(
        date: DateTime(2023, 10, 15),
        title: 'Event 2',
        description: 'This is the second event.',
      ),
      // 添加更多事件...
    ];
  }
}

class CalendarEvent {
  final DateTime date;
  final String title;
  final String description;

  CalendarEvent({required this.date, required this.title, required this.description});
}

代码说明

  1. 依赖管理:在 pubspec.yaml 文件中添加 flutter_customizable_calendar 依赖。
  2. 主应用MyApp 类定义了应用的主入口。
  3. 日历屏幕CalendarScreen 类是一个有状态的组件,包含主要的日历逻辑。
  4. 控制器:使用 CalendarController 来管理日历的状态。
  5. 样式定制:通过 CalendarHeaderStyle, CalendarEventStyle, CalendarSelectedDayStyle, 和 CalendarTodayStyle 类来自定义日历的不同部分。
  6. 事件数据_getEvents 方法返回一个事件列表,这些事件将在日历上显示。
  7. 事件回调onDaySelected, onTodayPressed, 和 onVisibleDaysChanged 回调用于处理用户交互。

你可以根据需要进一步定制和扩展这个示例,例如添加更多的事件、修改样式或者处理更多的用户交互。

回到顶部