资讯专栏INFORMATION COLUMN

[分享]iOS开发-通过修改UIdatePicker的字体颜色来认清Runtime的真相

Freelander / 408人阅读

摘要:找到苹果用于修改字体颜色的属性使用动态修改。在这个解决的过程中,我试过了遍历属性还有查看官方都找不到任何资料,甚至都想不通苹果内部是怎么处理的这么牛逼的。给设置参数,设置,并且动态调用设置参数苹果默认并且不开放其实也是的一种方式。

这篇文章对思路有极大的启迪性

本篇文章主要介绍了"通过修改UIdatePicker的字体颜色来认清Runtime的真相",主要涉及到方面的内容,对于IOS开发感兴趣的同学可以参考一下: 用过苹果原生UIdatePicker的Ios开发者都知道,UIdatePicker这个时间选择器的字体颜色默认的是黑色,并且官方API并没有提供可以修改字体颜色...

用过苹果原生UIdatePicker的Ios开发者都知道,UIdatePicker这个时间选择器的字体颜色默认的是黑色,并且官方API并没有提供可以修改字体颜色的API。如下:

UIDatePicker *picker = [[UIDatePicker alloc] init];
picker.datePickerMode = UIDatePickerModeDate;
picker.maximumDate = [NSDate dateWithTimeIntervalSince1970:0];
picker.minimumDate = [NSDate dateWithTimeIntervalSinceNow:10000];
[picker setDate:[NSDate date]];

做到上面这个效果,我主要进行了如下步骤:

利用通过遍历UIDatePicker类的所有属性,包括写在.m文件中看不到的属性。
找到苹果用于修改字体颜色的属性使用rumtime动态修改。
unsignedint outCount;

int i;
objc_property_t *pProperty = class_copyPropertyList([UIDatePicker class], &outCount);
for (i = outCount -1; i >= 0; i--)
{
    // 循环获取属性的名字   property_getName函数返回一个属性的名称NSString *getPropertyName = [NSString stringWithCString:property_getName(pProperty[i]) encoding:NSUTF8StringEncoding];
    NSString *getPropertyNameString = [NSString stringWithCString:property_getAttributes(pProperty[i]) encoding:NSUTF8StringEncoding];
    if([getPropertyName isEqualToString:@"textColor"])
    {
        [picker setValue:[UIColor whiteColor] forKey:@"textColor"];
    }

    NSLog(@"%@====%@",getPropertyNameString,getPropertyName);
}

以上代码中pProperty返回的是一个所有属性的数组,通过循环遍历我发现@”textColor”这个属性应该就是我想要的属性,然后通过setValue赋值白色,最后就做到了上图的结果。

或许说干过两年ios开发的都知道这个东西,但是笔者更想表达的还是这种分析问题和处理问题并最终解决问题的思想,当我们修改系统原生控件遇到瓶颈的时候可以采用这种方法来学习这个控件更多的特性

如果你觉得不过瘾?那就继续吧,更刺激的还在后面呢~

本来这个地方做好之后,结果测试测出一个非常奇葩的bug,就是UIDatepicker在当天的字体仍然是黑色。

看到了么,因为我在写这篇文章的时候是九月一号,所以九月一号的字体还是以前的黑色,比如说我动态改变系统日期为九月二号,它也会自动变成九月二号的字体是黑色,由于UI设计的是背景黑色,所以这里根本就看不清,严重影响产品体验。

通过一系列的纠结,我最后发现,如果UIDatepicker设置了最大时间(maxDate)和最小时间(minDate)就会这样,如果不设置就不出现这种情况,但是需求要限制最大时间和最小时间。
在这个解决的过程中,我试过了遍历属性还有查看官方API都找不到任何资料,甚至都想不通苹果内部是怎么处理的这么牛逼的。
实在没办法,我到处百度还是没进展,最后我终于在国外的网站找老外解决了这个问题(老外为啥比国人要牛逼呢?)
解决这个问题的核心代码如下:

        SEL selector = NSSelectorFromString(@"setHighlightsToday:");
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDatePicker instanceMethodSignatureForSelector:selector]];
        BOOL no = NO;
        [invocation setSelector:selector];
        [invocation setArgument:&no atIndex:2];
        [invocation invokeWithTarget:picker];
        

通过这个代码我不断的逆向推理其实现原理,并且各种百度查找NSInvocation的相关资料。
最后让我逐步来解析一下每一行代码的意思:

SEL selector = NSSelectorFromString(@”setHighlightsToday:”);

通过Runtime的NSSelectorFromString利用字符串获取方法@”setHighlightsToday:”(注意,看这个方法名就是今天的高亮显示开关,注意字符串后面的冒号,表示这个方法是有参数的)
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDatePicker instanceMethodSignatureForSelector:selector]];
用这个SEL创建UIdatepicker类的NSMethodSignature来创建一个NSInvocation。

BOOL no = NO;
[invocation setSelector:selector];
[invocation setArgument:&no atIndex:2];
[invocation invokeWithTarget:picker]; 

给invocation设置参数,设置target,并且动态调用设置参数NO(苹果默认YES并且不开放)
其实NSInvocation也是Runtime的一种方式。
注意[invocation setArgument:&no atIndex:2];这个2是怎么来的,因为setArgument中第一个参数的类picker,第二个参数是SEL,所以我们自己的参数最小的数字就是2,也就是这个方法的第一个参数

最后问题彻底解决了,晒张截图求真相:

虽然问题是最终解决了,但是假如下次我们又遇到这种类似的问题应该怎么办呢?难道又要焦头烂额的到处寻求援助么?程序员的上进心和求学心哪里去了?

最后笔者花了一到两天的时间一直思考这个问题,并最终通过分析老外的解决方式逆向找到解决的具体原理

前面说过,可以通过NSString *getPropertyName = [NSString stringWithCString:property_getName(pProperty[i]) encoding:NSUTF8StringEncoding];来获取一个类所有的属性,最后我在Runtime的API中发现,也可以获取一个类所有的方法(有兴趣的可以去了解一下IMP指针)。

unsigned int outCount;

int i;
Method *method = class_copyMethodList([UIDatePicker class],&outCount);

也就是说,利用Rumtime遍历某个类的所有属性和所有的方法,苹果的API限制在我们面前形同虚设,可以解决更多的一些原生API不开放的东西,其实这里也可以自己重写,不过相当麻烦,而且会有复杂的内存问题,所以还是直接用Runtime绕过苹果限制修改原生控件简单的多

其实runtime本身的东西很少,更多的是一些概念性的东西,有兴趣的也可以去了解一下runtime,本文主要讲的是一种利用runtime去解决实际问题的思维方式。


分享来源:
http://www.codes51.com/articl...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/16088.html

相关文章

  • 用UIPickerView简单定制一个UIDatePicker

    摘要:从类的继承关系上来看继承自继承自而这两个类之间并无继承关系。事实上,,和这三个是差不多的设计。直接讲如何定制。实现的思想是,首先要确定给出的时间范围,所有展示的选项不能超过这个范围。 做应用的时候免不了会对某些UI控件做一些样式上的定制,比如Button的背景色,圆角,阴影等元素的调整。UIDatePicker也是一个比较常用的UI控件,iOS 7简约的设计风格在某些场景下可能并不是很...

    zoomdong 评论0 收藏0
  • 分享iOS开发-datePicker详解

    摘要:日期选取器的各列会按照指定的风格进行自动配置,这样就让开发者不必关心如何配置表盘这样的底层操作。使用它只需要创建一个对象默认情况下选取会显示目前的日期和时间,并提供几个表盘,分别显示可以选择的月份和日期小时分钟以及上午下午。 UIDatePicker 是一个控制器类,封装了 UIPickerView,但是他是UIControl的子类,专门用于接受日期、时间和持续时长的输入。日期选取器的...

    aisuhua 评论0 收藏0
  • [经验]iOS开发-记录下在开发过程中遇到问题解决方案及经验总结-1

    摘要:返回上一级地址命令全球最大开源代码托管平台更改数量可使分量静态表示上传成功提交步骤此处后加空格更新代码提交是写在上边的的方法中全部属于异步下载。只将需要改变的值声明为变量。常量和变量必须在使用前声明,用来声明常量,用来声明变量。 声明:本文以下内容均摘自笔者从初学阶段至今的日常笔记,难免有才入门时的理解偏差,欢迎指出 本文长期更新(第二篇地址:传送门) 1.badgeVaule气泡提示...

    沈建明 评论0 收藏0
  • iOS开发③UIView

    摘要:用到的文本框的地方很多,比如搜索框用户登录框等。实现年活动指示器出于非活动状态时则会隐藏停止旋转开始旋转示例图步进器的作用是按照约定的步长进行增减操作。表示最小值,表示最大值,表示初始化时的值,表示步长。 UILabel Lable的作用是显示不可编辑的文字。 属性检查器 Text:Label显示的文字 Color:文字的颜色 Font:字体和字号 Alignment:文本的对齐方式...

    luck 评论0 收藏0
  • iOS相关

    摘要:多线程是通过提高资源网络请求之与的二次封装及意义之后,被苹果抛弃,该来的即便是迟些,但最终肯定会来。注意,不是线程安全的,但是线程安全的。也就是说,因为忙导致的触发时刻超出了的情况下,并不会取消,而不执行回调。 超简单!!! iOS 设置状态栏、导航栏按钮、标题、颜色、透明度,偏移等 // 一行代码搞定导航栏颜色navBarBarTintColor = .white// 一行代码搞定导...

    renweihub 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<