Flutter无限日历视图插件infinite_calendar_view的使用

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

Flutter无限日历视图插件infinite_calendar_view的使用

插件简介

Plugin Banner

infinite_calendar_view 是一个Flutter插件,允许你轻松实现所有日历UI。以下是该插件的主要特点:

  • 灵感来源于Outlook和Teams移动版:易于使用。
  • 三种视图:计划视图、月视图和列表视图。
  • 无限滚动:懒加载,提供最佳用户体验。
  • 高性能:即使每天有几十个预约也能流畅运行。
  • 完全可配置:所有内容都可以自定义!
  • 事件过滤:轻松过滤当天的事件。
  • 事件类型管理:管理全天事件和多天事件。
  • 可自定义显示天数:根据屏幕大小调整。
  • 捏合缩放:用两根手指改变时间刻度。
  • 拖拽功能:轻松移动预约。
  • 多列支持:在同一视图中管理多个日历!
  • 事件排列器:自定义安排预约的位置。

预览

Planner View

1 day 3 days
1 day 3 days

7 day (web or tablet) 7 day

Month View

Month View

List View

List View

安装

  1. 添加依赖pubspec.yaml 文件中:

    dependencies:
      infinite_calendar_view: ^最新版本号
    
  2. 执行 pub get

    flutter pub get
    
  3. 导入包

    import 'package:infinite_calendar_view/infinite_calendar_view.dart';
    

实现

初始化控制器

EventsController controller = EventsController();

添加日历视图

1 Day Planner View

Scaffold(
  body: EventsPlanner(
    controller: controller,
    daysShowed: 1,
  ),
);

3 Days Planner View

Scaffold(
  body: EventsPlanner(
    controller: controller,
    daysShowed: 3,
  ),
);

List View

Scaffold(
  body: EventsList(
    controller: controller,
  ),
);

添加或移除事件

添加事件

final event = Event(
  startTime: DateTime(2024, 8, 10, 8, 0),
  endTime: DateTime(2024, 8, 10, 9, 0),
  title: "Event1"
);

controller.updateCalendarData((calendarData) {
  calendarData.addEvents([event]);
});

添加全天事件

final fullDayEvent = FullDayEvent(
  title: "Full Day Event1"
);

controller.updateCalendarData((calendarData) {
  calendarData.addFullDayEvents(DateTime(2024, 8, 10), [fullDayEvent]);
});

跳转到特定日期

GlobalKey<InfiniteEventPlannerState> key = GlobalKey<InfiniteEventPlannerState>();

EventsPlanner(
  key: key,
  ...
);

key.currentState?.jumpToDate(DateTime(2024, 8, 10));

更多功能

捏合缩放

EventsPlanner(
  controller: controller,
  pinchToZoomParam: PinchToZoomParameters(
    pinchToZoom: true,
    onZoomChange: (heightPerMinute) {},
    pinchToZoomMinHeightPerMinute: 0.5,
    pinchToZoomMaxHeightPerMinute: 2.5,
    pinchToZoomSpeed: 1,
  ),
);

可拖拽事件

EventsPlanner(
  controller: controller,
  dayParam: DayParam(
    dayEventBuilder: (event, height, width, heightPerMinute) {
      return DraggableEventWidget(
        event: event,
        height: height,
        width: width,
        heightPerMinute: heightPerMinute,
        onDragEnd: (exactStartDateTime, exactEndDateTime, roundStartDateTime, roundEndDateTime) {
          moveEvent(event, roundStartDateTime, roundEndDateTime);
        },
        child: DefaultDayEvent(
          height: height,
          width: width,
          title: event.title,
          description: event.description,
        ),
      );
    },
  ),
);

void moveEvent(Event oldEvent, DateTime roundStartDateTime, DateTime roundEndDateTime) {
  controller.updateCalendarData((calendarData) {
    calendarData.updateEvent(
      oldEvent: oldEvent,
      newEvent: oldEvent.copyWith(
        startTime: roundStartDateTime,
        endTime: roundEndDateTime,
      ),
    );
  });
}

多列支持

Event(
  columnIndex: 2,
  ...
);

EventsPlanner(
  controller: controller,
  columnsParam: ColumnsParam(
    columns: 4,
    columnsLabels: ["Tennis", "Foot", "Bad"],
    columnsWidthRatio: [1 / 3, 1 / 3, 1 / 3],
    columnsColors: [
      Colors.yellow.pastel,
      Colors.green.pastel,
      Colors.blueAccent.pastel,
    ],
  ),
);

所有参数

Events Planner 参数

EventsPlanner(
  key: GlobalKey<EventsPlannerState>(),
  controller: controller,
  daysShowed: 3,
  initialDate: DateTime.now(),
  maxNextDays: 365,
  maxPreviousDays: 365,
  heightPerMinute: 1.0,
  initialVerticalScrollOffset: 1.0 * 7 * 60,
  daySeparationWidth: 3,
  onDayChange: (firstDay) {},
  onVerticalScrollChange: (offset) {},
  automaticAdjustHorizontalScrollToDay: true,
  onAutomaticAdjustHorizontalScroll: (day) {},
  horizontalScrollPhysics: const BouncingScrollPhysics(
    decelerationRate: ScrollDecelerationRate.fast,
  ),
  dayEventsArranger: SideEventArranger(paddingLeft: 0, paddingRight: 0),
  daysHeaderParam: DaysHeaderParam(
    daysHeaderVisibility: true,
    daysHeaderHeight: 40.0,
    daysHeaderColor: Theme.of(context).appBarTheme.backgroundColor,
    dayHeaderBuilder: (day, isToday) {
      return DefaultDayHeader(
        dayText: DateFormat("E d").format(day),
        isToday: isToday,
        foregroundColor: Colors.white,
      );
    },
  ),
  offTimesParam: OffTimesParam(
    offTimesAllDaysRanges: [
      OffTimeRange(
        TimeOfDay(hour: 0, minute: 0),
        TimeOfDay(hour: 7, minute: 0),
      ),
      OffTimeRange(
        TimeOfDay(hour: 18, minute: 0),
        TimeOfDay(hour: 24, minute: 0),
      )
    ],
    offTimesDayRanges: {
      DateTime(2024, 10, 8): [
        OffTimeRange(
          TimeOfDay(hour: 8, minute: 0),
          TimeOfDay(hour: 18, minute: 0),
        ),
      ],
    },
    offTimesColor: Color(0xFFF4F4F4),
    offTimesAllDaysPainter: (isToday, heightPerMinute, ranges, color) => OffSetAllDaysPainter(
        isToday, heightPerMinute, [], Color(0xFFF4F4F4)),
    offTimesDayPainter: (isToday, heightPerMinute, ranges, color) => OffSetAllDaysPainter(
        isToday, heightPerMinute, [], Color(0xFFF4F4F4)),
  ),
  dayParam: DayParam(
    todayColor: Colors.black12,
    dayTopPadding: 10,
    dayBottomPadding: 15,
    onSlotMinutesRound: 15,
    onSlotTap: (exactDateTime, roundDateTime) {},
    onSlotLongTap: (exactDateTime, roundDateTime) {},
    onSlotDoubleTap: (exactDateTime, roundDateTime) {},
    onDayBuild: (day) {},
    dayEventBuilder: (event, height, width, heightPerMinute) {
      return DefaultDayEvent(
        height: height,
        width: width,
        title: event.title,
        description: event.description,
      );
    },
    dayCustomPainter: (heightPerMinute, isToday) => LinesPainter(
      heightPerMinute: heightPerMinute,
      isToday: isToday,
      lineColor: Colors.black12,
    ),
  ),
  fullDayParam: FullDayParam(
    fullDayEventsBarVisibility: true,
    fullDayEventsBarLeftText: 'All day',
    fullDayEventsBarLeftWidget: Text('All day'),
    fullDayEventsBarHeight: 40,
    fullDayEventsBarDecoration: const BoxDecoration(
        border: Border(bottom: BorderSide(color: Colors.black12))),
  ),
  timesIndicatorsParam: TimesIndicatorsParam(
    timesIndicatorsWidth: 60.0,
    timesIndicatorsHorizontalPadding: 4.0,
    timesIndicatorsCustomPainter: (heightPerMinute) => HoursPainter(
      heightPerMinute: 1.0,
      showCurrentHour: true,
      hourColor: Colors.black12,
      halfHourColor: Colors.black12,
      quarterHourColor: Colors.black12,
      currentHourIndicatorColor: Colors.black12,
      halfHourMinHeightPerMinute: 1.3,
      quarterHourMinHeightPerMinute: 2,
    ),
  ),
  currentHourIndicatorParam: CurrentHourIndicatorParam(
    currentHourIndicatorHourVisibility: true,
    currentHourIndicatorLineVisibility: true,
    currentHourIndicatorColor: Colors.blue,
    currentHourIndicatorCustomPainter: (heightPerMinute, isToday) =>
        TimeIndicatorPainter(heightPerMinute, isToday, Colors.blue),
  ),
  pinchToZoomParam: PinchToZoomParameters(
    pinchToZoom: true,
    onZoomChange: (heightPerMinute) {},
    pinchToZoomMinHeightPerMinute: 0.5,
    pinchToZoomMaxHeightPerMinute: 2.5,
    pinchToZoomSpeed: 1,
  ),
);

Events List 参数

EventsList(
  controller: controller,
  initialDate: DateTime.now(),
  maxPreviousDays: 365,
  maxNextDays: 365,
  onDayChange: (day) {},
  todayHeaderColor: const Color(0xFFf4f9fd),
  verticalScrollPhysics: const BouncingScrollPhysics(
    decelerationRate: ScrollDecelerationRate.fast,
  ),
  dayEventsBuilder: (day, events) {
    return DefaultDayEvents(
      events: events,
      eventBuilder: (event) => DefaultDetailEvent(event: event),
      nullEventsWidget: DefaultDayEvents.defaultEmptyEventsWidget,
      eventSeparator: DefaultDayEvents.defaultEventSeparator,
      emptyEventsWidget: DefaultDayEvents.defaultEmptyEventsWidget,
    );
  },
  dayHeaderBuilder: (day, isToday) => DefaultHeader(
    dayText: DateFormat.MMMMEEEEd().format(day).toUpperCase(),
  ),
);

示例代码

以下是一个完整的示例代码,展示了如何在应用中使用 infinite_calendar_view 插件:

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

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

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  EventsController eventsController = EventsController();
  var calendarMode = CalendarView.day3;
  var darkMode = false;

  @override
  void initState() {
    super.initState();
    eventsController.updateCalendarData((calendarData) {
      // Add some sample events here
      calendarData.addEvents([
        Event(
          startTime: DateTime.now().add(Duration(hours: 1)),
          endTime: DateTime.now().add(Duration(hours: 2)),
          title: "Sample Event",
        ),
      ]);
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Infinite Calendar View',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.light,
        primaryColor: Colors.blue,
        appBarTheme: AppBarTheme(backgroundColor: Colors.blue),
        colorScheme: ColorScheme.fromSeed(
          brightness: Brightness.light,
          seedColor: Colors.blue,
          primary: Colors.blue,
        ),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.dark,
        appBarTheme: AppBarTheme(backgroundColor: Color(0xff2F2F2F)),
        colorScheme: ColorScheme.fromSeed(
          brightness: Brightness.dark,
          seedColor: Colors.blueAccent,
        ),
      ),
      themeMode: darkMode ? ThemeMode.dark : ThemeMode.light,
      home: Scaffold(
        appBar: AppBar(
          title: Text('Infinite Calendar View'),
        ),
        body: CalendarViewWidget(
            calendarMode: calendarMode,
            controller: eventsController,
            darkMode: darkMode),
      ),
    );
  }
}

class CalendarViewWidget extends StatelessWidget {
  const CalendarViewWidget({
    super.key,
    required this.calendarMode,
    required this.controller,
    required this.darkMode,
  });

  final CalendarView calendarMode;
  final EventsController controller;
  final bool darkMode;

  @override
  Widget build(BuildContext context) {
    return switch (calendarMode) {
      CalendarView.agenda => EventsListView(
          controller: controller,
        ),
      CalendarView.day => EventsPlannerOneDayView(
          key: UniqueKey(),
          controller: controller,
          isDarkMode: darkMode,
        ),
      CalendarView.day3 => EventsPlannerTreeDaysView(
          key: UniqueKey(),
          controller: controller,
          isDarkMode: darkMode,
        ),
      CalendarView.draggableDay3 => EventsPlannerDraggableEventsView(
          key: UniqueKey(),
          controller: controller,
          daysShowed: 3,
          isDarkMode: darkMode,
        ),
      CalendarView.day7 => EventsPlannerDraggableEventsView(
          key: UniqueKey(),
          controller: controller,
          daysShowed: 7,
          isDarkMode: darkMode,
        ),
      CalendarView.multi_column => EventsPlannerMultiColumnView(
          key: UniqueKey(),
          isDarkMode: darkMode,
        ),
      CalendarView.month => EventsMonthsView(
          controller: controller,
        ),
    };
  }
}

通过上述步骤,你可以快速上手并使用 infinite_calendar_view 插件来创建功能丰富的日历视图。希望这些信息对你有所帮助!如果有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter无限日历视图插件infinite_calendar_view的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter无限日历视图插件infinite_calendar_view的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用infinite_calendar_view插件来实现一个无限日历视图的示例代码。假设你已经添加了infinite_calendar_view到你的pubspec.yaml文件中,并且已经运行了flutter pub get

1. 添加依赖

首先,确保你的pubspec.yaml文件中包含以下依赖:

dependencies:
  flutter:
    sdk: flutter
  infinite_calendar_view: ^最新版本号  # 替换为实际的最新版本号

2. 导入插件

在你的Dart文件中导入infinite_calendar_view

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

3. 使用InfiniteCalendarView

下面是一个完整的示例,展示了如何使用InfiniteCalendarView

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

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

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

class _CalendarScreenState extends State<CalendarScreen> {
  DateTime _selectedDate = DateTime.now();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Infinite Calendar View'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Selected Date: ${_selectedDate.toLocal()}',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            Expanded(
              child: InfiniteCalendarView(
                firstDayOfWeek: Day.monday,
                initialSelectedDate: _selectedDate,
                onDateSelected: (DateTime date) {
                  setState(() {
                    _selectedDate = date;
                  });
                },
                onDateLongPressed: (DateTime date) {
                  // Handle long press event if needed
                  print('Long pressed on: $date');
                },
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(16),
                ),
                todayDecoration: BoxDecoration(
                  color: Colors.blue.withOpacity(0.3),
                  borderRadius: BorderRadius.circular(16),
                ),
                selectedDateDecoration: BoxDecoration(
                  color: Colors.blue.withOpacity(0.1),
                  borderRadius: BorderRadius.circular(16),
                ),
                weekdayTextStyle: TextStyle(fontSize: 14, color: Colors.grey),
                dayTextStyle: TextStyle(fontSize: 16),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

代码解释

  • 导入必要的包:导入了flutter/material.dartinfinite_calendar_view包。
  • 创建应用:使用MaterialApp创建应用,并设置主屏幕为CalendarScreen
  • 日历屏幕CalendarScreen是一个有状态的widget,它包含一个InfiniteCalendarView
  • 状态管理:使用_selectedDate变量来跟踪选中的日期,并在日期变化时更新UI。
  • 日历视图InfiniteCalendarView配置了各种参数,如firstDayOfWeekinitialSelectedDateonDateSelected回调等。
  • 装饰:设置了日历的装饰,包括普通日期、今天和选中日期的装饰,以及星期和日期的文本样式。

这个示例提供了一个基本的无限日历视图实现,你可以根据需要进一步自定义和扩展。

回到顶部