iOS备忘录iOS学习iOS开发资料收集区

XMDatePicker写作思路

2017-03-10  本文已影响197人  郭苒

先上一张效果图(原谅我还是这么无聊~~,我觉得动态的可能更能展示作品的特性)

0.gif
写这个时间选择器之前我还没写过相关的东西,没写过其实是瞎话,以前在项目中用过UIDatePicker,所以可自定义性不是很强,也没啥可说的,虽然在我们的项目中时间选择器很常见,但是认真研究的人就不知道了……,这次我也算是认真的看了一下UIPickerView内部的组成。先说说内部的组成吧。

1 UIPickerView内部组成

在xcode的可视化工具中你可以看到UIPikerView的结构如下:

1.png
当然如果,你也可以打印一下UIPikerView的子空间,会发现,它有三个子空间,其中两个是一样的,而且高度是0.67,所以我们可以猜测这个高度是0.67的view就是那两条灰色的分割线。不信你可以试试,简要做以下测试
 self.picker.subviews[1].hidden = YES;
 self.picker.subviews[2].hidden = YES;

此时,你会惊奇的发现两条灰色的分割线不见了,那么证实了我们猜测的是正确的,那么接下来往下走吧。再来看结构,如果说你嫌看结构图麻烦的话,你可以利用打印子控件的方式看查看其内部的控件,我是采用后者的,不过这里为了更加形象,我采用图形结合的方式来讲。如下图:


2.png

请原谅我的懒惰,这里我把结构图全部展开来讲吧,不再一张一张的贴图了,

2 为时间选择器自定义分割线

我们可以拿到UIPickerTableView然后利用runtime机制取出其内部的属性,如果你有印象的话,我说过每个UIPickerColumnView中有三个UIView控件,每个UIView控件中只有一个子控件UIPickerTableView,而三个UIView控件中的第3个才是我们选择时间的那一行。

上述话的意思简单翻译为UIPickerColumnViewUIView控件数 = UIPickerTableView

我们可以拿到每一列component( 即每一UIPickerColumnView列)中UIPickerTableView的数目

 int pickerTableViewNum = (int)self.picker.subviews[0].subviews[component].subviews.count;

遍历吧,记住第3个是选择日期的那一行

    for (int index = 0; index<pickerTableViewNum; index++) {
       //取出对应的UIPickerTableView
      UIView *tableView = self.picker.subviews[0].subviews[component].subviews[index].subviews[0];

       //取出UIPickerTableView内部的成员变量列表
        unsigned int count = 0;
        Ivar *array = class_copyIvarList([tableView class], &count);

        //遍历所有属性
        for (int i = 0; i<count; i++) {
            Ivar property = array[i];
            const char *string = ivar_getName(property);
            NSString *name = [[NSString alloc]initWithUTF8String:string];
            //找出名字为@"_referencingCells"的属性,取出它的值
            if (![name isEqualToString:@"_referencingCells"]) continue;
            NSMutableArray * cells = object_getIvar(tableView, property);

            int count = (int)cells.count;
            if(!count) continue;
            //设置字体颜色
            UIColor *textColor = nil;
            //设置label背景色
            UIColor *labelBackgroundColor = nil;
            //遍历UIPickerTableView 中的cell,并取出每个cell中的textLabel进行设置相关属性
            for (int i = 0; i< count; i++) {
                //设置其他部分的文字颜色、大小以及label背景等
                if (index !=pickerTableViewNum -1) {
                    font = self.otherTextFont? self.otherTextFont:[UIFont systemFontOfSize:16];
                    textColor = self.otherTextColor ? self.otherTextColor : [UIColor grayColor];
                    labelBackgroundColor = self.otherLabelColor ?self.otherLabelColor : [UIColor clearColor];
                }else{
                    font = self.selectedTextFont ? self.selectedTextFont : [UIFont systemFontOfSize:16];
                    textColor = self.selectedTextColor ? self.selectedTextColor : [UIColor blackColor];
                    labelBackgroundColor = self.selectedLabelColor ? self.selectedLabelColor : [UIColor clearColor];
                
                }
                
                UILabel *textLabel = [cells[i] subviews][1];
                textLabel.textColor = textColor;
                textLabel.font = font;
                textLabel.backgroundColor = labelBackgroundColor;
                
                if (index != pickerTableViewNum - 1)
                    continue;
                
                if (textLabel.subviews.count>=1)
                    continue;
                
                //dynamic seperator(设置动态分割线)
                if (self.pickerViewType == PickerViewTypeDynamicSperator) {
                    UIView *line = [[UIView alloc]initWithFrame:CGRectMake((textLabel.frame.size.width - textWidth)/2, textLabel.frame.size.height - 1, textWidth, 1)];
                    line.backgroundColor = self.seperateLineColor;
                    [textLabel addSubview:line];
                }
            }
        }
    }
    
    //static operate line(设置静态分割线)
    if (self.pickerViewType != PickerViewTypeStaticSperator) return;
//通过多次测试,可以粗略计算出每列之间的间隔大概是4.75
    CGFloat spacing = 4.75f;
    NSInteger numberOfComponent = [self numberOfComponents];
    CGFloat margin = (self.width - self.componentWidth * numberOfComponent - (numberOfComponent - 1)*spacing)/2;
    CGFloat textLabelOffSet = 9.0f;
    CGFloat textOffSet = (self.componentWidth - textLabelOffSet - textWidth)/2;
    //取出`UIPickerColumnView`中的最后一个 `UIView`控件
    UIView *view =  [self.picker.subviews[0].subviews[component].subviews lastObject];
    
   //UIView控件里面在修改前只有一个UIPickerTableView控件,我们需要添加静态分割线
    if (view.subviews.count>=3) {//不能多加啊
    }else{
        CGFloat x = (spacing+self.componentWidth)*component + margin + textLabelOffSet+textOffSet;
        UIView *lineView1 = [[UIView alloc]initWithFrame:CGRectMake(x, view.height - 1, textWidth, 1)];
        UIView *lineView2 = [[UIView alloc]initWithFrame:CGRectMake(x, 0, textWidth, 1)];
        lineView1.backgroundColor = [UIColor blueColor];
        lineView2.backgroundColor = [UIColor blueColor];
        [view addSubview:lineView1];
        [view addSubview:lineView2];
    }

上述代码基本是设置所有分割线部分的关键代码

3 关于日期的处理

这部分就不多做阐述了,主要是对每月天数的处理稍微复杂点,至于其他的基本好处理,我们只要知道1、3、5、7、8、10、12是31天,4、6、9、11是30天,2月份又分为平年和闰年,闰年29天,平年28天即可,许多demo种也有相关的计算,我觉得我代码中的书写应该也可以比较清晰的阐述,还有就是滑动的时的日期更新,我们需要注意一点儿小问题,如果想看内部实现的话欢迎大家看我的源码https://github.com/DreamOfXM/XMDatePicker.git
相关使用我已经在github
如果发现有什么问题,一定要给我提出来哦,当然也欢迎交流相关技术问题

上一篇 下一篇

猜你喜欢

热点阅读