欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS日历控件

程序员文章站 2022-04-15 16:48:50
项目需要,前一阵子重构了下iPad工程,添加了一个滚动无缝日历。 当时没有头绪,网上找了一个源码改吧改吧就上线了(参考链接),这个功能很多而且流畅性也特别好,推荐不会写的可以参考下。 这几天,活不太忙就把日历控件裁剪了下,做个最简单的滚动无缝日历。效果如下图: 日历可以左右滚动,点击某个日期后会变色 ......

项目需要,前一阵子重构了下ipad工程,添加了一个滚动无缝日历。

当时没有头绪,网上找了一个源码改吧改吧就上线了(参考链接),这个功能很多而且流畅性也特别好,推荐不会写的可以参考下。

这几天,活不太忙就把日历控件裁剪了下,做个最简单的滚动无缝日历。效果如下图:

iOS日历控件

 

日历可以左右滚动,点击某个日期后会变色,并且有回调。橘色的是标记日期,蓝色的是选择日期,蓝边的是当前日期,可以根据需要自行更改。

 

这个日历控件有两个比较复杂的地方:

  • uicollectionview默认情况下,横滚cell竖排竖滚cell横排,所以我们先要修改下cell的位置,自定义flowlayout继承于uicollectionviewflowlayout,重写它的preparelayout方法。
    iOS日历控件
    #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
    view code

     


  • 当你在当前月份点击了一个日期,滑到其他月份,然后要对刚才选择的月份的效果进行更改时,比较麻烦。刚开始我在didselectitematindexpath委托方法中用cellforitematindexpath进行获取时,不可见的cell获取不到返回的是空,然后在如何获取不可见的cell问题上纠结了两天,最终换了个解决方案,在cellforitematindexpath中进行了判断,解决了这个问题,当然点击后直接有响应跳转的话,刚才这个功能就很鸡肋了。具体看代码吧。

 

源码地址:https://github.com/zhanghua0926/excalendar