利用Runtime修改UIdatePicker的字体颜色

2024-09-02 16:08

本文主要是介绍利用Runtime修改UIdatePicker的字体颜色,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 用过苹果原生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]];

通过runtime处理之后的结果

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

  1. 利用通过遍历UIDatePicker类的所有属性,包括写在.m文件中看不到的属性。
  2. 找到苹果用于修改字体颜色的属性使用rumtime动态修改。
unsigned int 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的相关资料。
最后让我逐步来解析一下每一行代码的意思:

  1. SEL selector =NSSelectorFromString(@”setHighlightsToday:”);
    通过Runtime的NSSelectorFromString利用字符串获取方法@”setHighlightsToday:”(注意,看这个方法名就是今天的高亮显示开关,注意字符串后面的冒号,表示这个方法是有参数的)

  2. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDatePicker instanceMethodSignatureForSelector:selector]];
    用这个SEL创建UIdatepicker类的NSMethodSignature来创建一个NSInvocation。

  3. 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去解决实际问题的思维方式。

欢迎大家转载学习并且指出笔者不到之处,转载请注明出处哈!

这篇关于利用Runtime修改UIdatePicker的字体颜色的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1130428

相关文章

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

如何在运行时修改serialVersionUID

优质博文:IT-BLOG-CN 问题 我正在使用第三方库连接到外部系统,一切运行正常,但突然出现序列化错误 java.io.InvalidClassException: com.essbase.api.base.EssException; local class incompatible: stream classdesc serialVersionUID = 90314637791991

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 :frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可,不过需要覆盖所有目录下的图片。 由于是静态修改,则需要make一下,重新编译。 2、方法二Overlay方式 由于上述方法有很大缺点,修改多了之后容易遗忘自己修改哪些文件,为此我们采用另外一种方法,使用Overlay方式。

Golang进程权限调度包runtime

关于 runtime 包几个方法: Gosched:让当前线程让出 cpu 以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行GOMAXPROCS:设置最大的可同时使用的 CPU 核数Goexit:退出当前 goroutine(但是defer语句会照常执行)NumGoroutine:返回正在执行和排队的任务总数GOOS:目标操作系统NumCPU:返回当前系统的 CPU 核数量 p

hibernate修改数据库已有的对象【简化操作】

陈科肇 直接上代码: /*** 更新新的数据并并未修改旧的数据* @param oldEntity 数据库存在的实体* @param newEntity 更改后的实体* @throws IllegalAccessException * @throws IllegalArgumentException */public void updateNew(T oldEntity,T newEntity

SW - 引入第三方dwg图纸后,修改坐标原点

文章目录 SW - 引入第三方dwg图纸后,修改坐标原点概述笔记设置图纸新原点END SW - 引入第三方dwg图纸后,修改坐标原点 概述 在solidworks中引入第三方的dwg格式图纸后,坐标原点大概率都不合适。 全图自动缩放后,引入的图纸离默认的原点位置差很多。 需要自己重新设置原点位置,才能自动缩放后,在工作区中间显示引入的图纸。 笔记 将dwg图纸拖到SW中

linux下修改系统日期与时间

cp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime

Windows11电脑上自带的画图软件修改照片大小(不裁剪尺寸的情况下)

针对一张图片,有时候上传的图片有大小限制,那么在这种情况下如何修改其大小呢,在不裁剪尺寸的情况下 步骤如下: 1.选定一张图片,右击->打开方式->画图,如下: 第二步:打开图片后,我们可以看到图片的大小为82.1kb,点击上面工具栏的“重设大小和倾斜”进行调整,如下: 第三步:修改水平和垂直的数字,此处我修改为分别都修改为50,然后保存,可以看到大小变成63.5kb,如下:

【第0007页 · 数组】数组中重复的数据(如何实现数组的原地修改)

【前言】本文以及之后的一些题解都会陆续整理到目录中,若想了解全部题解整理,请看这里: 第0007页 · 数组中重复的数据         今天,我们来看一个在实际工作中运用不多,但是对于一些算法题还是有必要的奇技淫巧——数组的原地修改。下面我们将通过两道题目来学习这种技巧。 【找到所有数组中消失的数】 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1,

渐变颜色填充

GradientFill函数可以对特定的矩形区域或者三角形区域进行渐变颜色的填充。我们先来看看GradientFill函数到底长得什么样子,帅不帅。 [cpp]  view plain copy print ? BOOL GradientFill(     _In_  HDC hdc,     _In_  PTRIVERTEX pVertex,     _In_  ULONG