flutter 自定义日历选择

禁止转载、抄袭

功能需求

实现后是长这样的(因为项目要以底部弹窗显示,也可以整个UI自定义)
要代码的私信我(看人品回复)

项目需求:

  1. 星期一在第一,星期日在最后
  2. 一开始显示的是当前月份
  3. 有startTime和endTime的限制,所以并不是每个日期都能选择
  4. 选择全部工作日按钮,意思是除了星期六日和第三点的条件都选择
  5. 已选统计选了多少天,下一步把选择的传到下个页面
  6. 没有说需不需要滑动切换月份(我是没做了)
  7. 在第3点外的月份不能点击全选
  8. 新增一个带回显的功能

干就完事了

我看了日历第三方库,有些符合要求,但有些不符合要求(淦),看了原理直接手撕算了。

实际原理就是gradeview(iOS里的collectionView),里面添数据而已,就是处理数据比较麻烦,幸好没叫我做滑动。

说这么多,上核心代码

因为部分是项目的代码,我不可能公开,你需要的话可以私信我,女的请私信你的qq(感觉不可能)

工具类

这些函数的dateTime date都是该月的第一天,其他不管用(主要是自己懒得再重新处理数据)

///星期一为第一天static int computeFirstDay(DateTime date, MaterialLocalizations localizations) {final int weekdayFromMonday = date.weekday;final int firstDayOfWeekFromSunday = localizations.firstDayOfWeekIndex + 1;final int firstDayOfWeekFromMonday = firstDayOfWeekFromSunday % 7;return (weekdayFromMonday - firstDayOfWeekFromMonday) % 7;}static const List<int> _daysInMonth = <int>[31,-1,31,30,31,30,31,31,30,31,30,31];/// 获取这个月的天数static int getDayCountInMonth(DateTime date) {int month = date.month;int year = date.year;if (month == DateTime.february) {final bool isLeapYear =(year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);if (isLeapYear) return 29;return 28;}return _daysInMonth[month-1];}

这些大概是定位该月gradeView(collectionView)的显示数据位置。

UI方面的代码我不怎么想给,毕竟产品+UI都不一样

调用

List<DateModel> list = [];List<DateTime> returnList = [];List<TotalDateModel> totalList = [];bool isfullChoice = false;bool canChooseMoon = true;
@overridevoid initState() {super.initState();WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {setState(() {list = getDateModel(MaterialLocalizations.of(context));});});}class DateModel {int day;bool isChoosen;DateModel({required this.day,required this.isChoosen,});
}

创建原始数据

///创建数据List<DateModel> getDateModel(MaterialLocalizations localizations){//当月的总天数final int currentMonthTotalDays = CommonUtils.getMonthDay(widget.date);//每月的一号对应的周几(星期一在第二天)若星期一第一天就-1final int firstDayIsWeekInMonth = CommonUtils.computeFirstDay(widget.date, localizations);final List<DateModel> dayList = [];for(int i = 0;i < firstDayIsWeekInMonth; i++) {final DateModel model = DateModel(day: 0,isChoosen: false);dayList.add(model);}for(int i = 1; i <= currentMonthTotalDays; i ++) {final DateModel model = DateModel(day: i,isChoosen: false);dayList.add(model);}return dayList;}

切换月份

//切换月份处理事件 isRight为1 就+月,-1就-月void changeMonth(int isRight) {//寻找list里的元素内容,若找不到返回orelse TotalDateModeltotalList.firstWhere((element) => element.date == widget.date, orElse: () {final TotalDateModel newModel = TotalDateModel(date: widget.date, dateList: list);totalList.add(newModel);return newModel;}).dateList = list;final DateTime nextDate = DateTime(widget.date.year, widget.date.month + isRight, widget.date.day);widget.date = nextDate;if(widget.goNextMonth != null) {widget.goNextMonth(widget.date);}list = totalList.firstWhere((element) => element.date == nextDate, orElse: () {list = getDateModel(MaterialLocalizations.of(context));final TotalDateModel newModel = TotalDateModel(dateList: list);return newModel;}).dateList;//是否全选final int firstDayIsWeekInMonth =CommonUtils.computeFirstDay(widget.date, MaterialLocalizations.of(context));isfullChoice = true;canChooseMoon = true;///遍历date的数组,起始时间和终止时间内falsefor (int j = firstDayIsWeekInMonth; j < list.length; j++) {final int index = list[j].day + firstDayIsWeekInMonth;if(index%7 != 0 && (index + 1)%7 != 0){if (list[j].isChoosen == false) {final DateTime dateTime = DateTime(widget.date.year,widget.date.month,list[j].day);final epochTime = dateTime.millisecondsSinceEpoch;if ((widget.model.validStartDate ?? 0) <= epochTime && epochTime <= (widget.model.validEndDate ?? 0)){isfullChoice = false;break;}}}}///该月份是否能点击全选final int startTime = DateTime(widget.date.year,widget.date.month,1).millisecondsSinceEpoch;final int endTime = DateTime(widget.date.year,widget.date.month,list[list.length - 1].day).millisecondsSinceEpoch;if((widget.model.validStartDate ?? 0) > endTime || (widget.model.validEndDate ?? 0) < startTime) {canChooseMoon = false;isfullChoice = false;}setState(() {});}

全选按钮

void chooseAllAction() {//每月的一号对应的周几(星期一在第二天)若星期一第一天就-1final int firstDayIsWeekInMonth = CommonUtils.computeFirstDay(widget.date, MaterialLocalizations.of(context));//反选if(isfullChoice) {for(int i = firstDayIsWeekInMonth;i < list.length;i++){if (list[i].isChoosen) {final int index = list[i].day + firstDayIsWeekInMonth;if(index%7 != 0 && (index + 1)%7 != 0){final DateTime dateTime = DateTime(widget.date.year,widget.date.month,list[i].day);final epochTime = dateTime.millisecondsSinceEpoch;if ((widget.model.validStartDate ?? 0) <= epochTime && epochTime <= (widget.model.validEndDate ?? 0)){list[i].isChoosen = false;returnList.remove(dateTime);}}}}}else {      //正选for(int i = firstDayIsWeekInMonth;i < list.length;i++){if (!list[i].isChoosen) {final int index = list[i].day + firstDayIsWeekInMonth;if(index%7 != 0 && (index + 1)%7 != 0){final DateTime dateTime = DateTime(widget.date.year,widget.date.month,list[i].day);final epochTime = dateTime.millisecondsSinceEpoch;if ((widget.model.validStartDate ?? 0) <= epochTime &&epochTime <= (widget.model.validEndDate ?? 0)){if (list[i].isChoosen == false) {returnList.add(dateTime);}list[i].isChoosen = true;}}}}}setState(() {isfullChoice = !isfullChoice;});}

点击单个item的处理事件

onTap: (){//每月的一号对应的周几(星期一在第二天)若星期一第一天就-1final int firstDayIsWeekInMonth = CommonUtils.computeFirstDay(widget.date, MaterialLocalizations.of(context));final DateTime dateTime = DateTime(widget.date.year,widget.date.month,list[i].day);final epochTime = dateTime.millisecondsSinceEpoch;if ((widget.model.validStartDate ?? 0) <= epochTime && epochTime <= (widget.model.validEndDate ?? 0)){list[i].isChoosen = !list[i].isChoosen;if(list[i].isChoosen){isfullChoice = true;returnList.add(dateTime);for(int j = firstDayIsWeekInMonth;j < list.length;j++){if(list[j].isChoosen == false) {final int index = list[j].day + firstDayIsWeekInMonth;if(index%7 != 0 && (index + 1)%7 != 0){isfullChoice = false;break;}}}}else {final int index = list[i].day + firstDayIsWeekInMonth;returnList.remove(dateTime);if(index%7 != 0 && (index + 1)%7 != 0){isfullChoice = false;}}}

次要的判断高度

double getBottomSheetHeight(DateTime date) {//当月的总天数final int currentMonthTotalDays = CommonUtils.getMonthDay(date);//每月的一号对应的周几(星期一在第二天)若星期一第一天就-1final int firstDayIsWeekInMonth = CommonUtils.computeFirstDay(date, MaterialLocalizations.of(context));final int line = ((currentMonthTotalDays + firstDayIsWeekInMonth)%7).toInt() == 0 ? 0 : 1;final lines = ((currentMonthTotalDays + firstDayIsWeekInMonth)/7).toInt();int column = lines + line ;final itemHeight = MediaQuery.of(context).size.width/7 ;return column * itemHeight + 15;}

回显功能

带回显的功能,就需要闭包传值返回,也就是上下文传递

///回显void Function(List<TotalDateModel> totalList,List<DateModel> list,List<DateTime> returnList,bool isFullChoice,bool canChooseMoon,) callBackData;

在点击退出和点下一步的时候调用这个闭包,把该页面所需要的值回传。

定义的话就需要把闭包回传的值返回到这个页面

// DateTime date;MealOrderDetailModel model;String schoolName;int schoolId;int productId;DateTime date;///存储上下月的数据List<TotalDateModel> totalList;///页面需要的基础listList<DateModel> list;///点击后加进去的值List<DateTime> returnList;///全选按钮bool isFullChoice;///startTime和endTime之外bool canChooseMoon;MealOrderCalendar({Key? key,required this.date,required this.model,required this.schoolName,required this.productId,required this.schoolId,required this.list,required this.totalList,required this.goNextMonth,required this.callBackData,required this.returnList,required this.canChooseMoon,required this.isFullChoice,}): super(key: key);

私有变量初始化赋值,我一开始用 widge.xxxx作为数据源时,出现错误(页面不更新),所以是需要私有变量来处理数据源

@overridevoid initState() {super.initState();_totalList = widget.totalList;_list = widget.list;_date = widget.date;_isFullChoice = widget.isFullChoice;_canChooseMoon = widget.canChooseMoon;_returnList = widget.returnList;WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {if(_list.isEmpty) {setState(() {_list = getDateModel(MaterialLocalizations.of(context));});}});}

分享了这么多点个赞不过分吧

flutter 自定义日历选择(没有用到第三方日历库)相关推荐

  1. Flutter自定义圆形选择框

    flutter自带的checkbox是方形的,需要圆形可以自定义一个,用法一样: import 'package:flutter/material.dart'; class RoundCheckBox ...

  2. flutter 自定义日历

    在项目中需要实现一个日历展示我发布过的动态,效果如图,同时需要左右滑动翻页 尝试使用组件发现可自定义的范围比较小,且无法实现需求,看到这篇Flutter自定义日历,实现日期底部不同颜色的日历事件_ap ...

  3. 纵享丝滑滑动切换的周月日历,水滴效果,丰富自定义日历样式,仿小米日历(ViewDragHelper实现)...

    本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发 老规矩先贴效果图 github地址,觉得有帮助的可以给个 star 呗 github.com/idic779/mo ...

  4. html页面酒店日历插件,基于vue2.x的酒店日历选择插件

    基于vue2.x的酒店日历选择插件 效果图 快速使用安装: npm install -S vue-hotel-calendar 或者 yarn add vue-hotel-calendar 使用: i ...

  5. .NET DataGridView 单元格添加日历选择控件

    .NET 使用datagridview 在单元格中加入日历选择控件的方法 在最近的项目改动中,需要在单元格的日期列中用日历选择的方式提供选择,翻阅了许多的资料 终于还是解决了问题 现在记录一下学习过程 ...

  6. 日历2019日历备注_如何在Windows 10日历应用中使用Google日历

    日历2019日历备注 With the arrival of Windows 10, we've been greeted with a new slew of functionality-based ...

  7. Flutter 自定义聊天气泡

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-frjkn3p5-1626132866799)(https://ducafecat.tech/2021/07/13/tra ...

  8. 谷歌 订阅日历_如何在Google日历中订阅您喜欢的运动队的时间表

    谷歌 订阅日历 If you're anything like me, you basically schedule your life around your favorite sports tea ...

  9. 【Flutter】Flutter 自定义字体 ( 下载 TTF 字体 | pubspec.yaml 配置字体资源 | 同步资源 | 全局应用字体 | 局部应用字体 )

    文章目录 一.Flutter 自定义字体 1.ttf 字体文件 2.ttf 字体资源配置 3.获取字体 4.全局使用字体 5.局部使用字体 二.完整代码示例 三.相关资源 一.Flutter 自定义字 ...

最新文章

  1. 【Java 网络编程】TCP API 简介 ( Socket | ServerSocket )
  2. 吉特仓库管理系统-- 后台管理开源啦,源码大放送
  3. 不包含本位置值的累乘数组
  4. “打头办”不在百度,在民间
  5. 笔记-高项案例题-2017年下-整体管理-变更管理
  6. 组会PPT20200910《大工HPT放电结果错误剖析》
  7. android高级编程实操期末机试试题,《网络高级编程》201001机考试题A
  8. 【转】Maven 手动添加 JAR 包到本地仓库
  9. V4L2摄像头取数据程序
  10. acm中c语言标准输入输出,ACM竞赛之输入输出
  11. xp精简版 安装IIS
  12. Revisiting RCNN: On Awakening the Classification Power of Faster RCNN解读
  13. 怎样更改计算机管理员用户名,Administrator怎么修改账户用户名教程
  14. 用c语言编写打猎小游戏,使用c语言编写简单小游戏.docx
  15. Postman+Newman命令运行
  16. 2022~2023年杂记之
  17. [数据分析实例5]使用python-pandas对历届世界杯数据进行数据分析,并用matplotlib绘图,干货满满,赶紧收藏学习起来!
  18. GPT-5将死于GPT-4背刺?牛津剑桥研究警告:AI训AI成「剧毒」,会让模型崩溃!
  19. Jass 技能模型定义(—):半人马酋长的反击光环
  20. 时文阅读-03-23

热门文章

  1. 硬核来袭!中国AI大模型峰会,开发者不容错过这场夏季盛会
  2. hyperledger fabric chaincode 教程二
  3. 【​区块链】相关专业名词术语
  4. ZeroMQ的订阅发布(publish-subscribe)模式
  5. 需要什么PCB封装,照着弄就好了
  6. 自主可控桌面操作系统替换的思考
  7. 小额免密交易的条件有那些
  8. excel匹配两列数据
  9. Git 常用设置|别名、邮箱、免密
  10. 基于Java实现的宠物领养、救助、商城系统网站设计(springboot+bootstrap+MySQL)