XMDatePicker写作思路

作者: 郭苒 | 来源:发表于2017-03-10 12:21 被阅读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

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

  • UIPickerView的suviews 展开这个后我们看到里面又有3个UIPickerColumnView,当然你可以利用日志打印一下,会发现前三个是完全一样的,我们可以猜测每一个代表着一列,不信你可以改变数据源试试,会发现猜测的正确性。
  • 接下来我们进入到每一列UIPickerColumnView,发现有三个UIView(子控件),前两个完全一样,第三个不同,我猜测,第三个是中间行,也就是选择到日期的那一行
  • 以此类推,你可以看到中间行里面有一个子控件,名字是UIPickerTableView,这是苹果内部私有类,在UIKit框架中我们找不到它的头文件,但是依旧不影响我们获取到它。
    快上代码,不多啰嗦了

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
如果发现有什么问题,一定要给我提出来哦,当然也欢迎交流相关技术问题

相关文章

  • XMDatePicker写作思路

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

  • 写作思路

    1,分解集合名词。(unhealthy eating habits)->(eating irregularly, ...

  • 写作思路

    25岁, 应该是一个应该成熟,或者即将成熟的年纪, 对爱情, 对未来, 对当下, 对自己的迷茫、彷徨、交流、不长...

  • 写作思路

    (做出假设)描述感受、经历——引发思考——提出解决方法最后,放肆地书写一个孤独灵魂的自由。

  • 写作思路

    三十余年,阿金辗转四地辛勤耕耘育桃李,风风雨雨的人生经历和五彩缤纷的社会现象,给了阿金一个又一个的心灵触动,一次又...

  • 写作思路

    虾线,精致生活的反思 点评陷阱 靠点评生存的企业分析 从加油站与4s店说起非充分竞争现象

  • 写作思路

    最近在看《大泼猴》,挺不错的一本网络小说。很明显能看出这本小说是作者从《西游记》这本经典名著产生的写作思路。 之前...

  • 写作思路

    三十余年,阿金辗转四地辛勤耕耘育桃李,风风雨雨的人生经历和五彩缤纷的社会现象,给了阿金一个又一个的心灵触动,给了阿...

  • 写作思路

    写作是一个自我修行的过程,是整理自身思路、书写自己对这个世界感觉和认知的方法. 但是我个人现在更多的写作人,失去了...

  • 写作思路

    昨天家长让我帮小朋友辅导作文,仔细思考后,却陷入了思维误区~ 作业的标题是favorite cookie,最喜爱的...

网友评论

  • long弟弟:设置fromYear程序会崩溃,抽时间解决下吧,感谢!
    郭苒:相关代码已更新,如有问题请及时告知,谢谢
    郭苒:不好意思啊,最近忙,没及时回复,这两个属性已经过期了,没及时注销,抱歉啊,现在都是maximumDate和minimumDate
  • iaiayao:看了代码后发现没有设置最大日期和最小日期的限制,这个可以完善一下
    iaiayao:@郭苒 :+1:
    郭苒:@melody_yoo 你说的最大时间和最小时间已经更新,另外将整个代码框架都进行了较大的调整,请知悉
    郭苒:@melody_yoo 谢谢,本想找时间重构一下代码的,哈哈,回家就很懒了……我会尽快完善
  • IT:self.picker.subviews[1].hidden = YES;
    self.picker.subviews[2].hidden = YES;
    会奔溃啊
    郭苒:单独隐藏这两条线是不会崩溃的,可参看我的源码里- (void)p_setSelectedRowTitleLabelOfComponent:(NSInteger)component这个方法,至于说你的崩溃,我没看你是怎么写的,所以也不好说
  • Vincent20481:直接打赏了
    郭苒:谢谢!

本文标题:XMDatePicker写作思路

本文链接:https://www.haomeiwen.com/subject/crengttx.html