iOS日历控件
程序员文章站
2022-07-09 20:28:09
项目需要,前一阵子重构了下iPad工程,添加了一个滚动无缝日历。 当时没有头绪,网上找了一个源码改吧改吧就上线了(参考链接),这个功能很多而且流畅性也特别好,推荐不会写的可以参考下。 这几天,活不太忙就把日历控件裁剪了下,做个最简单的滚动无缝日历。效果如下图: 日历可以左右滚动,点击某个日期后会变色 ......
项目需要,前一阵子重构了下ipad工程,添加了一个滚动无缝日历。
当时没有头绪,网上找了一个源码改吧改吧就上线了(参考链接),这个功能很多而且流畅性也特别好,推荐不会写的可以参考下。
这几天,活不太忙就把日历控件裁剪了下,做个最简单的滚动无缝日历。效果如下图:
日历可以左右滚动,点击某个日期后会变色,并且有回调。橘色的是标记日期,蓝色的是选择日期,蓝边的是当前日期,可以根据需要自行更改。
这个日历控件有两个比较复杂的地方:
-
uicollectionview默认情况下,横滚cell竖排竖滚cell横排,所以我们先要修改下cell的位置,自定义flowlayout继承于uicollectionviewflowlayout,重写它的preparelayout方法。
#import "excalendarcollectionviewflowlayout.h" @interface excalendarcollectionviewflowlayout () @property (nonatomic, strong) nsmutablearray *allattributes; @end @implementation excalendarcollectionviewflowlayout - (void)preparelayout { [super preparelayout]; self.allattributes = [nsmutablearray array]; nsinteger sections = [self.collectionview numberofsections]; for (int i = 0; i < sections; i++) { // setup one section attributes. nsmutablearray *tmparray = [nsmutablearray array]; nsinteger count = [self.collectionview numberofitemsinsection:i]; for (nsinteger j = 0; j < count; j++) { nsindexpath *indexpath = [nsindexpath indexpathforitem:j insection:i]; uicollectionviewlayoutattributes *attributes = [self layoutattributesforitematindexpath:indexpath]; [tmparray addobject:attributes]; } [self.allattributes addobject:tmparray]; } } - (cgsize)collectionviewcontentsize { return [super collectionviewcontentsize]; } - (uicollectionviewlayoutattributes *)layoutattributesforitematindexpath:(nsindexpath *)indexpath { nsinteger item = indexpath.item; nsinteger x; nsinteger y; // 根据item的序号计算出item的行列位置 [self targetpositionwithitem:item resultx:&x resulty:&y]; // 根据已得出的item的行列位置,将item放入indexpath中对应的位置。 nsinteger item2 = [self orignitematx:x y:y]; nsindexpath *thenewindexpath = [nsindexpath indexpathforitem:item2 insection:indexpath.section]; uicollectionviewlayoutattributes *thenewattr = [super layoutattributesforitematindexpath:thenewindexpath]; thenewattr.indexpath = indexpath; return thenewattr; } - (nsarray<uicollectionviewlayoutattributes *> *)layoutattributesforelementsinrect:(cgrect)rect { nsarray *attributes = [super layoutattributesforelementsinrect:rect]; nsmutablearray *tmp = [nsmutablearray array]; for (uicollectionviewlayoutattributes *attr in attributes) { for (nsmutablearray *attributes in self.allattributes) { for (uicollectionviewlayoutattributes *attr2 in attributes) { if (attr.indexpath.item == attr2.indexpath.item) { [tmp addobject:attr2]; break; } } } } return tmp; } // 根据item计算目标item的位置。 - (void)targetpositionwithitem:(nsinteger)item resultx:(nsinteger *)x resulty:(nsinteger *)y { // nsinteger page = item / (self.itemcountperrow * self.rowcountperpage); nsinteger thex = item % self.itemcountperrow; nsinteger they = item / self.itemcountperrow; if (x != null) { *x = thex; } if (y != null) { *y = they; } } - (nsinteger)orignitematx:(nsinteger)x y:(nsinteger)y { nsinteger item = x * self.rowcountperpage + y; return item; } @end
- 当你在当前月份点击了一个日期,滑到其他月份,然后要对刚才选择的月份的效果进行更改时,比较麻烦。刚开始我在didselectitematindexpath委托方法中用cellforitematindexpath进行获取时,不可见的cell获取不到返回的是空,然后在如何获取不可见的cell问题上纠结了两天,最终换了个解决方案,在cellforitematindexpath中进行了判断,解决了这个问题,当然点击后直接有响应跳转的话,刚才这个功能就很鸡肋了。具体看代码吧。
源码地址:https://github.com/zhanghua0926/excalendar