iOS 簡約日曆控件EBCalendarView

EBCalendarView日曆控件,調用簡單,代碼簡潔。git

github地址:https://github.com/woheduole/EBCalendarViewgithub

效果圖

EBCalendarView.gif

調用示例

EBCalendarView *calendarView = [[EBCalendarView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds), 0)];
    calendarView.delegate = self;
    //calendarView.maxLastMonths = 0;  
    //calendarView.maxNextMonths = 0;
    [self.view addSubview:calendarView];
複製代碼
- (void)calendarView:(EBCalendarView*)calendarView didSelectedDate:(NSDate*)date {
    NSLog(@"選中日期:%@", [date stringWithFormat:@"yyyy-MM-dd"]);
}
複製代碼

代碼目錄

code.png

思路

  • EBCalendarView
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:self.flowLayout];
        _collectionView.dataSource = self;
        _collectionView.delegate = self;
        _collectionView.showsVerticalScrollIndicator = NO;
        _collectionView.showsHorizontalScrollIndicator = NO;
        _collectionView.backgroundColor = [UIColor whiteColor];
        [_collectionView registerClass:[EBCalendarDayCell class] forCellWithReuseIdentifier:kEBCalendarViewReuseIdentifier];
複製代碼
_flowLayout.itemSize = CGSizeMake(viewWidth / kEBCalendarViewCellColumn, kEBCalendarViewCellHeight);
複製代碼

經過UICollectionView控件去顯示日期數據,設置UICollectionViewFlowLayout的itemSize,高度能夠固定,寬度就是用視圖的總寬度去除以7。bash

// 小數向上取整
    NSInteger rows = ceilf(_dates.count / kEBCalendarViewCellColumn);
    self.frame = ({
        CGRect frame = self.frame;
        frame.size.height = kEBCalendarViewWeekViewHeight + kEBCalenderNavigationViewHeight + (rows * kEBCalendarViewCellHeight);
        frame;
    });
複製代碼

切換月份的時候,因爲每個月的1號所在星期是不一致的,會致使行數不同,好比一個月是31天,它的1號是星期日,這時候日期會有6行,若是它的1號是星期一,那麼它會顯示5行,這裏會根據行數去動態的改變其高度。app

- (NSDate *)dateByAddingMonths:(NSInteger)months {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setMonth:months];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}
複製代碼

月份在累加或累減的時候,經過NSCalendar類直接增長月數,這樣就不用本身去處理2018-12點擊下個月切換到2019-01或者2019-01點擊上個月切換到2018-12的操做了。佈局

  • EBCalendarModel 數據模型
@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger month;
@property (nonatomic, assign) NSInteger day;
// 記錄選中狀態
@property (nonatomic, assign, getter=isSelected) BOOL selected;
// 是否爲當天
@property (nonatomic, assign, getter=isToday) BOOL today;
// 將year,month,day轉換成NSDate
@property (nonatomic, strong, readonly) NSDate *date;
複製代碼
- (NSDate*)date {
    if (_year == 0 || _month == 0 || _day == 0) {
        return nil;
    }
    return [NSDate dateWithString:[NSString stringWithFormat:@"%zd-%zd-%zd"
                            , _year
                            , _month
                            , _day] format:@"yyyy-MM-dd"];
}
複製代碼
  • EBCalenderWeekView 周視圖
- (void)layoutSubviews {
    [super layoutSubviews];
    [self createWeekView];
}

- (void)setWeeks:(NSArray *)weeks {
    _weeks = weeks;
    [self createWeekView];
}

- (void)createWeekView {
    CGFloat viewWidth = CGRectGetWidth(self.bounds)
    , viewHeight = CGRectGetHeight(self.bounds);
    if (_weeks.count == 0 || viewHeight == 0) return;
    [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    NSInteger weekCount = _weeks.count;
    CGFloat weekWidth = viewWidth / weekCount;
    for (int n = 0; n < weekCount; n ++ ) {
        NSString *week =  _weeks[n];
        UILabel *weekLabel = [[UILabel alloc] initWithFrame:CGRectMake(weekWidth * n, 0, weekWidth, viewHeight)];
        weekLabel.font = [UIFont systemFontOfSize:14];
        weekLabel.textColor = [UIColor colorWithHexString:@"333333"];
        weekLabel.textAlignment = NSTextAlignmentCenter;
        weekLabel.text = week;
        [self addSubview:weekLabel];
    }
}
複製代碼

根據傳入的參數weeks動態添加UILabel顯示週數據。ui

  • EBCalenderNavigationView 月份導航視圖
- (void)changeMonthAction:(UIButton*)button {
    BOOL isNextMonth = NO;
    if ([button isEqual:_nextMonthButton]) {
        // 下個月
        isNextMonth = YES;
    }
    if ([self.delegate respondsToSelector:@selector(calenderNavigationViewDidChangeMonth:isNextMonth:)]) {
        [self.delegate calenderNavigationViewDidChangeMonth:self isNextMonth:isNextMonth];
    }
}
複製代碼

這裏面主要就顯示左右箭頭和中間的年月顯示,左右箭頭是兩個UIButton,在點擊它們的時候經過代理把動做給傳到EBCalendarView視圖。atom

  • UIColor+EBAdd 顏色輔助類
+ (UIColor *)colorWithHexString:(NSString *)hexString {
    NSScanner *scanner = [NSScanner scannerWithString:hexString];
    unsigned hexNum;
    if (![scanner scanHexInt:&hexNum]) return nil;
    return [UIColor colorWithRGBHex:hexNum];
}

+ (UIColor *)colorWithRGBHex:(UInt32)hex {
    int r = (hex >> 16) & 0xFF;
    int g = (hex >> 8) & 0xFF;
    int b = (hex) & 0xFF;
    
    return [UIColor colorWithRed:r / 255.0f
                           green:g / 255.0f
                            blue:b / 255.0f
                           alpha:1.0f];
}
複製代碼

代碼中顏色都是用的16進制的顏色值,純屬我的習慣。spa

  • NSDate+EBAdd 日期輔助類
// 該方法來源自YYKit
- (NSInteger)year;

// 該方法來源自YYKit
- (NSInteger)month;

// 該方法來源自YYKit
- (NSInteger)day;

// 該方法來源自YYKit
- (NSInteger)weekday;

// 該方法來源自YYKit
- (BOOL)isToday;

// 當前月有多少天
- (NSUInteger)numberOfDaysInMonth;

// 該方法來源自YYKit
- (NSString *)stringWithFormat:(NSString *)format;

// 該方法來源自YYKit
- (NSDate *)dateByAddingMonths:(NSInteger)months;

// 該方法來源自YYKit
+ (NSDate *)dateWithString:(NSString *)dateString format:(NSString *)format;
複製代碼

小結:UICollectionView很強大的一個控件,經過UICollectionViewFlowLayout去重寫佈局,能夠實現不少酷炫的功能。這裏的日曆控件只是設置了item的寬高,屬於很基礎的使用。其中須要注意兩點:1.每月的1號是屬於周幾,而後去設置它的起始位置;2.每月有多少天。app類型不同也會致使日曆控件實際呈現方式不同,基本邏輯都同樣,無非就是一些細微的控制。3d

相關文章
相關標籤/搜索