在项目中需要实现一个日历展示我发布过的动态,效果如图,同时需要左右滑动翻页
尝试使用组件发现可自定义的范围比较小,且无法实现需求,看到这篇Flutter自定义日历,实现日期底部不同颜色的日历事件_apro-wang的博客-CSDN博客_flutter自定义日历后进行了一些修改最终实现了需要的效果
//日历组件
import 'package:domain/user/model/publish_project.dart';
import 'package:flutter/material.dart';
import 'package:be_real/config/global_style.dart';
import 'package:domain/user/repository/user_repository.dart';
import 'package:data/repository_module.dart';
import 'package:be_real/view/account/components/delete_memory.dart';
import 'package:be_real/event/manager.dart';
import 'package:event_bus/event_bus.dart';
class Calender extends StatefulWidget {
const Calender({Key key}) : super(key: key);
@override
_CalenderState createState() => _CalenderState();
}
class _CalenderState extends State<Calender> {
int _year = DateTime.now().year; //当前展示年
int _month = DateTime.now().month; //当前展示月
int _day = DateTime.now().day; //当前展示日
List _datas = []; //日期数组--只展示一个月份
List _recentPublish = []; //我的当前展示月发布--某一天未发布赋值null
List<Project> _myPublishAll = []; //我的全部动态--接口获取
UserRepository _userRepository = userRepository();
@override
void initState() {
//设置默认当前月日期
_setDatas(year: _year, month: _month);
//获取我的全部动态
_getMyPublishAll();
//刷新我的全部动态
Manager.refreshMyPublishAll = EventBus();
Manager.refreshMyPublishAll.on().listen((event) async {
print('刷新我的全部动态');
_getMyPublishAll();
});
super.initState();
}
//获取我发布的所有动态--接口获取
_getMyPublishAll() async {
await _userRepository.getMyselfPublishAll().then((value) async {
await setState((){
_myPublishAll = value.isSuccess;
});
print('我的最近发布:${_myPublishAll}');
await _loadAttendanceMonthRecord();
});
}
//赋值我的当前展示月发布
_loadAttendanceMonthRecord() async {
await setState(() {
for(int i = 0; i < _datas.length; i++){ //外层循环当前展示月日期数组
for(int j = 0; j < _myPublishAll.length; j++){ //内层循环我发布的动态数组
if(_datas[i] == _myPublishAll[j].createDate){
_recentPublish[i] = _myPublishAll[j];
break;
}
}
}
});
print('本月发布:${_recentPublish}');
}
@override
Widget build(BuildContext context) {
double movedXStart = 0;
double movedXEnd = 0;
double movedYStart = 0;
double movedYEnd = 0;
return Scaffold(
backgroundColor: GlobalStyle.mainThemeColor,
body: SingleChildScrollView(
child: Column(
children: [
GestureDetector(
onHorizontalDragStart: (DragStartDetails details) {
movedXStart = details.globalPosition.dx;
movedYStart = details.globalPosition.dy;
},
onHorizontalDragUpdate: (DragUpdateDetails details) {
movedXEnd = details.globalPosition.dx;
movedYEnd = details.globalPosition.dy;
},
onHorizontalDragEnd: (DragEndDetails details) {
if((movedYEnd - movedYStart).abs() < (movedXEnd - movedXStart).abs()){ //横向移动距离大于纵向移动距离时判定为此时在进行横向滑动
if (movedXEnd - movedXStart < 0) { //左滑,执行下一月
_nextMonth();
}else{ //右滑,执行上一月
_lastMonth();
}
}
},
child: Container(
child: Column(
children: [
_yearHeader(),
_weekHeader(),
_everyDay(),
],
),
),
),
],
)));
}
//头部年
Widget _yearHeader() {
return Container(
margin: EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
_lastMonth();
},
child: Container(
margin: EdgeInsets.only(left: 20),
child: Image.asset(
"assets/commons/left_white.png",
width: 24,
height: 24,
),
),
),
Text(
"$_year 年$_month 月",
style: const TextStyle(
fontSize: 16,
color: Colors.white,
fontWeight: FontWeight.w700
),
),
GestureDetector(
onTap: () {
_nextMonth();
},
child: Container(
margin: EdgeInsets.only(right: 20),
child: Image.asset(
"assets/commons/right_white.png",
width: 24,
height: 24,
),
),
),
],
),
);
}
//中部周
Widget _weekHeader() {
var array = ["一", "二", "三", "四", "五", "六", "日"];
return Container(
height: 50,
alignment: Alignment.center,
child: GridView.builder(
padding: EdgeInsets.only(left: 10, right: 10),
itemCount: array.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7, //每行7列
crossAxisSpacing: 5, //横轴间距
mainAxisSpacing: 20, //纵轴间距
),
itemBuilder: (context, index) {
return Container(
alignment: Alignment.center,
child: Text(
array[index],
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w700
),
));
},
),
);
}
//底部日
Widget _everyDay() {
return Container(
child: GridView.builder(
padding: EdgeInsets.only(left: 10, top: 10, right: 10),
itemCount: _getRowsForMonthYear(year: _year, month: _month) * 7,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7, //每行7列
crossAxisSpacing: 5, //横轴间距
mainAxisSpacing: 20, //纵轴间距
),
itemBuilder: (context, index) {
Project project = _recentPublish[index];
return GestureDetector(
onTap: () {
project == null ? null : DeleteMemory(context, project);
},
child: project == null
? Container(
//设置底部背景
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: Center(
child: Text(
//不是当前月不显示值
int.parse(_datas[index].substring(5,7)) == _month
? _datas[index].substring(8,10)
: "",
style: const TextStyle(
fontSize: 16,
color: Color(0xFF5A5A5C),
fontWeight: FontWeight.w700
)
),
),
)
: Container(
//设置底部背景
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
image: DecorationImage(
image: NetworkImage(
project.worksPhotoAfter,
),
//不是当月不显示图片
opacity: int.parse(_datas[index].substring(5,7)) == _month ? 1 : 0,
fit: BoxFit.cover
)
),
child: Center(
child: Text(
//不是当前月不显示值
int.parse(_datas[index].substring(5,7)) == _month
? _datas[index].substring(8,10)
: "",
style: const TextStyle(
fontSize: 16,
color: Color(0xFFFFFFFF),
fontWeight: FontWeight.w700
)
),
),
),
);
},
),
);
}
// 获取行数
int _getRowsForMonthYear({int year, int month}) {
//当前月天数
var _currentMonthDays = _getCurrentMonthDays(year: year, month: month);
//补齐空缺需要的天数
var _placeholderDays = _getPlaceholderDays(year: year, month: month);
//以2022年11月为例,本月30天,第一天为周二,补齐第一天前面的空缺需要1天,30+1=31为本月天数在日历中的占位数
int rows = (_currentMonthDays + _placeholderDays) ~/ 7;
//若不能被7整除,则行数在取整行数上+1
int remainder = (_currentMonthDays + _placeholderDays) % 7;
if (remainder > 0) {
rows = rows + 1;
}
return rows;
}
// weekday得到这个月的第一天是星期几
// 因为该日历的每行是从周一开始,因此获取到本月的第一天是周几后需要-1得到还需要多少天补齐前面的空缺
int _getPlaceholderDays({int year, int month}) {
return DateTime(year, month).weekday - 1 % 7;
}
// 获取当前月份天数
int _getCurrentMonthDays({int year, int month}) {
if (month == 2) {
//判断2月份是闰年月还是平年
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) {
return 29;
} else {
return 28;
}
} else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
return 31;
} else {
return 30;
}
}
/// 获取展示信息
_setDatas({int year, int month}) {
/// 上个月占位--以本月为2022年11月为例,10.31在11月占位
var lastYear = year;
var lastMonth = month - 1;
if (month == 1) {
lastYear = year - 1;
lastMonth = 12;
}
var placeholderDays = _getPlaceholderDays(year: year, month: month); //补齐本月第一天前的空缺需要的天数
var lastMonthDays = _getCurrentMonthDays(year: lastYear, month: lastMonth); //上个月天数
var firstDay = lastMonthDays - placeholderDays;
for (var i = 0; i < placeholderDays; i++) {
_datas.add(
'${_dateFormat(lastYear)}-${_dateFormat(lastMonth)}-${_dateFormat(firstDay+i+1)}'
);
_recentPublish.add(null);
}
/// 本月显示
var currentMonthDays = _getCurrentMonthDays(year: year, month: month); //本月天数
for (var i = 0; i < currentMonthDays; i++) {
_datas.add(
'${_dateFormat(_year)}-${_dateFormat(_month)}-${_dateFormat(i+1)}'
);
_recentPublish.add(null);
}
/// 下个月占位--以本月为2022年11月为例,12月1-4日在11月占位
var nextYear = year;
var nextMonth = month + 1;
if (month == 12) {
nextYear = year + 1;
nextMonth = 1;
}
var nextPlaceholderDays = _getPlaceholderDays(year: nextYear, month: nextMonth); //下个月补齐空缺需要的天数
for (var i = 0; i < 7 - nextPlaceholderDays; i++) {
_datas.add(
'${_dateFormat(nextYear)}-${_dateFormat(nextMonth)}-${_dateFormat(i+1)}'
);
_recentPublish.add(null);
}
print('本月日期:${_datas}');
print('创造当前月发布数组:${_recentPublish}');
}
//日期格式化-加0
_dateFormat(int num){
if(num < 10){
return '0$num';
}else{
return '$num';
}
}
// 上月
_lastMonth() {
setState(() {
//当前月是1月,上个月就是上一年的12月
if (_month == 1) {
_year = _year - 1;
_month = 12;
} else {
_month = _month - 1;
}
_day = 1; //查看上一个月时,默认选中的为第一天
_datas.clear();
_recentPublish.clear();
_setDatas(year: _year, month: _month);
//更新月历事件
_loadAttendanceMonthRecord();
});
}
// 下月
_nextMonth() {
//判断展示年是否小于当前年,若是则操作上下月不受限制
if(_year < DateTime.now().year){
_setNextMonthData();
}
//判断展示年是否是当前年,若是则需要再判断月份
else if(_year == DateTime.now().year){
//当展示月大于等于当前月时,不能点击下个月,反之则需要设置下个月数据
if(_month < DateTime.now().month){
_setNextMonthData();
}
}
}
//设置下个月的数据
_setNextMonthData(){
setState(() {
//当前月是12月,下个月就是下一年的1月
if (_month == 12) {
_year = _year + 1;
_month = 1;
} else {
_month = _month + 1;
}
if (_month == DateTime.now().month) {
//如果下个月时当前月,默认选中当天
_day = DateTime.now().day;
} else {
//如果不是当前月,默认选中第一天
_day = 1;
}
_datas.clear();
_recentPublish.clear();
_setDatas(year: _year, month: _month);
//更新月历事件
_loadAttendanceMonthRecord();
});
}
}