You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
xiaodong 6dcf7c21a2
创建configuration类,将配置的信息放到这里
5 years ago
.idea 创建example的module 5 years ago
example 创建configuration类,将配置的信息放到这里 5 years ago
lib 创建configuration类,将配置的信息放到这里 5 years ago
.gitignore 删除根目录 5 years ago
.metadata 删除根目录 5 years ago
CHANGELOG.md 创建configuration类,将配置的信息放到这里 5 years ago
LICENSE 删除根目录 5 years ago
README.md 创建configuration类,将配置的信息放到这里 5 years ago
flutter_custom_calendar.iml 删除根目录 5 years ago
pubspec.lock 创建configuration类,将配置的信息放到这里 5 years ago
pubspec.yaml 创建configuration类,将配置的信息放到这里 5 years ago

README.md

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

FlutterCalendarWidget

Flutter上的一个日历控件可以定制成自己想要的样子。

主要功能

  • 支持公历,农历,节气,传统节日,常用节假日
  • 日期范围设置默认支持的最大日期范围为1971.01-2055.12
  • 禁用日期范围设置,比如想实现某范围的日期内可以点击,范围外的日期置灰
  • 支持单选、多选模式,提供多选超过限制个数的回调和多选超过指定范围的回调。
  • 跳转到指定日期,默认支持动画切换
  • 自定义日历Item支持组合widget的方式和利用canvas绘制的方式
  • 自定义顶部的WeekBar
  • 根据实际场景可以给Item添加自定义的额外数据实现各种额外的功能。比如实现进度条风格的日历实现日历的各种标记
  • 支持周视图的展示
  • 支持月份视图和星期视图的展示与切换联动

近期修改

[1.0.0] - 2019/9/22

  • 重构日历的代码,进行性能优化
  • 创建configuration类将配置的信息放到这里
  • 引入provider状态管理,避免深层嵌套传递信息
  • 实现周视图,并实现周视图和月视图之间的联动
  • DateModel增加isCurrentMonth用于绘制月视图可以屏蔽一些非当前月份的日子前面几天或者后面几天的isCurrentMonth是为false的。

[0.0.1] - 2019/5/19.

  • 支持公历,农历,节气,传统节日,常用节假日
  • 日期范围设置默认支持的最大日期范围为1971.01-2055.12
  • 禁用日期范围设置,比如想实现某范围的日期内可以点击,范围外的日期置灰
  • 支持单选、多选模式,提供多选超过限制个数的回调和多选超过指定范围的回调。
  • 跳转到指定日期,默认支持动画切换
  • 自定义日历Item支持组合widget的方式和利用canvas绘制的方式
  • 自定义顶部的WeekBar
  • 可以给Item添加自定义的额外数据实现各种额外的功能。比如实现进度条风格的日历

使用

在pubspec.yaml添加依赖:

flutter_custom_calendar:
    git:
      url: https://github.com/LXD312569496/flutter_custom_calendar.git

引入flutter_custom_calendar,就可以使用CalendarViewWidget配置CalendarController就可以了。

import 'package:flutter_custom_calendar/flutter_custom_calendar.dart';

CalendarViewWidget({@required this.calendarController, this.boxDecoration});
  • boxDecoration用来配置整体的背景
  • 利用CalendarController来配置一些数据并且可以通过CalendarController进行一些操作或者事件监听比如滚动到下一个月获取当前被选中的Item等等。

配置CalendarController

下面是CalendarController中一些支持自定义配置的属性。不配置的话会有对应的默认值。

个人觉得配置的含义主要包括了3个方面的配置。

  • 一个是显示日历所需要的相关数据,
  • 一个是显示日历的自定义UI的相关配置
  • 一个是对日历的监听事件进行配置。
      //构造函数
      CalendarController(
      {int selectMode = Constants.MODE_SINGLE_SELECT,
      bool expandStatus = true,
      DayWidgetBuilder dayWidgetBuilder = defaultCustomDayWidget,
      WeekBarItemWidgetBuilder weekBarItemWidgetBuilder = defaultWeekBarWidget,
      int minYear = 1971,
      int maxYear = 2055,
      int minYearMonth = 1,
      int maxYearMonth = 12,
      int nowYear = -1,
      int nowMonth = -1,
      int minSelectYear = 1971,
      int minSelectMonth = 1,
      int minSelectDay = 1,
      int maxSelectYear = 2055,
      int maxSelectMonth = 12,
      int maxSelectDay = 30,
      Set<DateTime> selectedDateTimeList = EMPTY_SET,
      DateModel selectDateModel,
      int maxMultiSelectCount = 9999,
      double verticalSpacing = 10,
      bool enableExpand = true,
      Map<DateModel, Object> extraDataMap = EMPTY_MAP})

数据方面的配置

属性 含义 默认值
selectMode 选择模式,表示单选或者多选 默认是单选MODE_SINGLE_SELECT
minYear 日历显示的最小年份 1971
maxYear 日历显示的最大年份 2055
minYearMonth 日历显示的最小年份的月份 1
maxYearMonth 日历显示的最大年份的月份 12
nowYear 日历显示的当前的年份 -1
nowMonth 日历显示的当前的月份 -1
minSelectYear 可以选择的最小年份 1971
minSelectMonth 可以选择的最小年份的月份 1
minSelectDay 可以选择的最小月份的日子 1
maxSelectYear 可以选择的最大年份 2055
maxSelectMonth 可以选择的最大年份的月份 12
maxSelectDay 可以选择的最大月份的日子 30注意不能超过对应月份的总天数
selectedDateList 被选中的日期,用于多选 默认为空Set, Set selectedDateList = new Set()
selectDateModel 当前选择项,用于单选 默认为空
maxMultiSelectCount 多选,最多选多少个 hhh
extraDataMap 自定义额外的数据 默认为空MapMap<DateTime, Object> extraDataMap = new Map()

UI绘制相关的配置

属性 含义 默认值
weekBarItemWidgetBuilder 创建顶部的weekbar 默认样式
dayWidgetBuilder 创建日历item 默认样式

事件监听的配置

方法 含义 默认值
void addMonthChangeListener(OnMonthChange listener) 月份切换事件
void addOnCalendarSelectListener(OnCalendarSelect listener) 点击选择事件
void addOnMultiSelectOutOfRangeListener(OnMultiSelectOutOfRange listener) 多选超出指定范围
void addOnMultiSelectOutOfSizeListener(OnMultiSelectOutOfSize listener) 多选超出限制个数
void addExpandChangeListener(ValueChanged expandChange) 监听日历的展开收缩状态

利用controller来控制日历的切换支持配置动画

方法 含义 默认值
Future previousPage() 滑动到上一个页面会自动根据当前的展开状态滑动到上一个月或者上一个星期。如果已经在第一个页面没有上一个页面就会返回false其他情况返回true
Future nextPage() 滑动到下一个页面会自动根据当前的展开状态滑动到下一个月或者下一个星期。如果已经在最后一个页面没有下一个页面就会返回false其他情况返回true
void moveToCalendar(int year, int month, int day, {bool needAnimation = false,Duration duration = const Duration(milliseconds: 500),Curve curve = Curves.ease}) 到指定日期
void moveToNextYear() 切换到下一年
void moveToPreviousYear() 切换到上一年
void moveToNextMonth() 切换到下一个月份
void moveToPreviousMonth() 切换到上一个月份
void toggleExpandStatus() 切换展开状态

利用controller来获取日历的一些数据信息

方法 含义 默认值
DateTime getCurrentMonth() 获取当前的月份
Set getMultiSelectCalendar() 获取被选中的日期,多选
DateModel getSingleSelectCalendar() 获取被选中的日期,单选

如何自定义UI

包括自定义WeekBar、自定义日历Item默认使用的都是DefaultXXXWidget。

只要继承对应的Base类实现相应的方法然后只需要在配置Controller的时候实现相应的Builder方法就可以了。

//支持自定义绘制
DayWidgetBuilder dayWidgetBuilder; //创建日历item
WeekBarItemWidgetBuilder weekBarItemWidgetBuilder; //创建顶部的weekbar

自定义WeekBar

继承BaseWeekBar重写getWeekBarItem(index)方法就可以。随便你怎么实现只需要返回一个Widget就可以了。

class DefaultWeekBar extends BaseWeekBar {
  const DefaultWeekBar({Key key}) : super(key: key);
  @override
  Widget getWeekBarItem(int index) {
    /**
    * 自定义Widget
    */
    return new Container(
      height: 40,
      alignment: Alignment.center,
      child: new Text(
        Constants.WEEK_LIST[index],
        style: topWeekTextStyle,
      ),
    );
  }
}

自定义日历Item

提供两种方法一种是利用组合widget的方式来创建一种是利用Canvas来自定义绘制Item。最后只需要在CalendarController的构造参数中进行配置就可以了。

  • 继承BaseCombineDayWidget重写getNormalWidget(DateModel dateModel) 和getSelectedWidget(DateModel dateModel)就可以了返回对应的widget就行。
class DefaultCombineDayWidget extends BaseCombineDayWidget {
  DefaultCombineDayWidget(DateModel dateModel) : super(dateModel);

  @override
  Widget getNormalWidget(DateModel dateModel) {
     //实现默认状态下的UI
  }

  @override
  Widget getSelectedWidget(DateModel dateModel) {
    //绘制被选中的UI
  }
}
  • 继承BaseCustomDayWidget重写drawNormal和drawSelected的两个方法就可以了利用canvas自己绘制Item。
class DefaultCustomDayWidget extends BaseCustomDayWidget {
  DefaultCustomDayWidget(DateModel dateModel) : super(dateModel);
  @override
  void drawNormal(DateModel dateModel, Canvas canvas, Size size) {
    //实现默认状态下的UI
    defaultDrawNormal(dateModel, canvas, size);
  }
  @override
  void drawSelected(DateModel dateModel, Canvas canvas, Size size) {
    //绘制被选中的UI
    defaultDrawSelected(dateModel, canvas, size);
  }
}

根据实际场景自定义额外的数据extraData

自定义每个item的进度条数据

    //外部处理每个dateModel所对应的进度
    Map<DateModel, int> progressMap = {
      DateModel.fromDateTime(temp.add(Duration(days: 1))): 0,
      DateModel.fromDateTime(temp.add(Duration(days: 2))): 20,
      DateModel.fromDateTime(temp.add(Duration(days: 3))): 40,
      DateModel.fromDateTime(temp.add(Duration(days: 4))): 60,
      DateModel.fromDateTime(temp.add(Duration(days: 5))): 80,
      DateModel.fromDateTime(temp.add(Duration(days: 6))): 100,
    };
    //创建CalendarController对象的时候将extraDataMap赋值就行了
    new CalendarController(
        extraDataMap: progressMap)
    //绘制DayWidget的时候可以直接从dateModel的extraData对象中拿到想要的数据
    int progress = dateModel.extraData;

自定义各种标记

 //外部处理每个dateModel所对应的标记
 Map<DateModel, String> customExtraData = {
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -1))): "假",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -2))): "游",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -3))): "事",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -4))): "班",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -5))): "假",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: -6))): "游",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 2))): "游",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 3))): "事",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 4))): "班",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 5))): "假",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 6))): "游",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 7))): "事",
    DateModel.fromDateTime(DateTime.now().add(Duration(days: 8))): "班",
  };
    //创建CalendarController对象的时候将extraDataMap赋值就行了
    new CalendarController(
        extraDataMap: customExtraData)
    //绘制DayWidget的时候可以直接从dateModel的extraData对象中拿到想要的数据
   String data = dateModel.extraData;

DateModel实体类

日历所用的日期的实体类DateModel有下面这些属性。可以在自定义绘制DayWidget的时候根据相应的属性进行判断后绘制相应的UI。

属性 含义 类型 默认值
year 年份 int
month 月份 int
day 日期 int 默认为1
lunarYear 农历年份 int
lunarMonth 农历月份 int
lunarDay 农历日期 int
lunarString 农历字符串 String
solarTerm 24节气 String
gregorianFestival gregorianFestival String
traditionFestival 传统农历节日 String
isCurrentDay 是否是今天 bool false
isLeapYear 是否是闰年 bool false
isWeekend 是否是周末 bool false
isInRange 是否在范围内,比如可以实现在某个范围外,设置置灰的功能 bool false
isSelected 是否被选中,用来实现一些标记或者选择功能 bool false
extraData 自定义的额外数据 Object 默认为空
方法 含义
DateTime getDateTime() 将DateModel转化成DateTime
DateModel fromDateTime(DateTime dateTime) 根据DateTime创建对应的model并初始化农历和传统节日等信息
bool operator ==(Object other) 重写==方法可以判断两个dateModel是否是同一天

TODO LIST

  • 优化代码实现
  • 继续写几个不同风格的Demo
  • 支持手势操作