使用 UIPickerView 制作的日历

@implementation CalendarByDicViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor colorWithRed:0.93 green:0.93 blue:0.93 alpha:1];
    
    UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(110, 50, 100, 33)];
    lab.text = @"日 历";
    lab.textAlignment = NSTextAlignmentCenter;
    lab.textColor = [UIColor colorWithRed:155/255.0 green:155/255.0 blue:155/255.0 alpha:1];
    lab.font = [UIFont boldSystemFontOfSize:24];
    [self.view addSubview:lab];
    
    UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 100, 320, 50)];
    pickerView.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:pickerView];
 
    pickerView.dataSource = self;
    pickerView.delegate = self;
    
    //存储年份的数组
    NSMutableArray *yearArray = [[NSMutableArray alloc] initWithCapacity:50];
    for (int i = 0; i < 50; i ++)
    {
        [yearArray addObject:[NSString stringWithFormat:@"%d", START_YEAR + i]];
    }
    //存储月份的数组
    NSMutableArray *monthArray = [[NSMutableArray alloc] initWithCapacity:12];
    for (int i = 0; i < 12; i ++)
    {
        [monthArray addObject:[NSString stringWithFormat:@"%d", i + 1]];
    }
    //存储天数的数组
    NSMutableArray *dayArray = [[NSMutableArray alloc] initWithCapacity:31];
    for (int i = 0; i < 31; i ++)
    {
        [dayArray addObject:[NSString stringWithFormat:@"%d", i + 1]];
    }
    
    //将年、月、日都存放进字典
    _dataDic = [[NSDictionary alloc] initWithObjectsAndKeys:yearArray, @"year", monthArray, @"month", dayArray, @"day", nil];
    
    //计算今天的日期
    NSDate *date = [NSDate date];
    date = [date dateByAddingTimeInterval:8 * 60 * 60];
    NSString *today = [date description];
    int yearNow = [[today substringToIndex:4] intValue];
    int monthNow = [[today substringWithRange:NSMakeRange(5, 2)] intValue];
    int dayNow = [[today substringWithRange:NSMakeRange(8, 2)] intValue];
    
    //日期指定到今天,让日历默认显示今天的日期
    [pickerView selectRow:(yearNow - START_YEAR) inComponent:0 animated:NO];
    [pickerView selectRow:(monthNow - 1) inComponent:1 animated:NO];
    [pickerView selectRow:(dayNow - 1) inComponent:2 animated:NO];
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
    return _dataDic.count; //设置选择器的列数,即显示年、月、日三列
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
    NSArray *keyArray = [_dataDic allKeys];
    NSArray *contentArray = [_dataDic objectForKey:keyArray[component]];
    //显示每月的天数跟年份和月份都有关系,所以需要判断条件
    if (component == 2)
    {
        int month = [pickerView selectedRowInComponent:1] + 1;
        int year = [pickerView selectedRowInComponent:0] + START_YEAR;
        switch (month)
        {
            //每个月的天数不一样
            case 4: case 6: case 9: case 11:
            {
                contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 30)];//4、6、9、11月的天数是30天
                return contentArray.count;
            }
            case 2:
            {
                if ( [self isLeapYear:year])
                {
                    //如果是闰年,二月有 29 天
                    contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 29)];
                }
                else
                {
                    //不是闰年,二月只有 28 天
                    contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 28)];
                }
                
                return contentArray.count;
            }
            default:
                return contentArray.count;  //1、3、5、7、8、10、12 月的天数都是31天
        }
    }

    return contentArray.count;  //返回每列的行数
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
{
    return 100; //设置每列的宽度
}

- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component
{
    return 50; //设置每行的高度
}

//设置所在列每行的显示标题,与设置所在列的行数一样,天数的标题设置仍旧需要非一番功夫
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
    NSArray *keyArray = [_dataDic allKeys];
    NSArray *contentArray = [_dataDic objectForKey:keyArray[component]];
    
    if (component == 2)
    {
        int month = [pickerView selectedRowInComponent:1] + 1;
        int year = [pickerView selectedRowInComponent:0] +START_YEAR;
        switch (month)
        {
            case 4: case 6: case 9: case 11:
            {
                contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 30)];
                return contentArray[row];
            }
            case 2:
            {
                if ( [self isLeapYear:year])
                {
                    //闰年
                    contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 29)];
                }
                else
                {
                    contentArray = [contentArray subarrayWithRange:NSMakeRange(0, 28)];
                }
                
                return contentArray[row];
            }
            default:
                return contentArray[row];
        }
    }
    return contentArray[row];
}

//当选择的行数改变时触发的方法
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    //第一列的被选择行变化,即年份改变,则刷新月份和天数
    if (component == 0)
    {
        [pickerView reloadAllComponents]; //刷新月份与日期
        //下面是将月份和天数都定位到第一行
        [pickerView selectRow:0 inComponent:1 animated:YES];
        [pickerView selectRow:0 inComponent:2 animated:YES];
    }
    //第二列的被选择行变化,即月份发生变化,刷新天这列的内容
    if (component == 1)
    {
        [pickerView reloadAllComponents];
        [pickerView selectRow:0 inComponent:2 animated:YES];
    }//需要这些条件的原因是年份和月份的变化,都会引起每月的天数的变化,他们之间是有联系的,要掌握好他们之间的对应关系
}

//判断是否闰年
- (BOOL)isLeapYear:(int)year
{
    if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)))
    {
        return YES; //是闰年返回 YES
    }
    
    return NO; //不是闰年,返回 NO
}
@end

写这个程序的时候,数组越界的问题快把我给整疯了,回头检查代码的时候一直没找到问题出在哪了,后来重新理了遍思路,其实想法是没错的,估计是来回倒腾就出错了。这时候就需要自己静下心来在重新梳理一遍,大问题没有,这种小错误也是要命的。

代码中用到了字典,也可以直接用数组实现,不过像尝试一下字典,在代码方面也没有简洁多少...

原文地址:https://www.cnblogs.com/hyhl23/p/4189220.html