博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何修复UITextField在iOS10文字下沉问题
阅读量:6256 次
发布时间:2019-06-22

本文共 4150 字,大约阅读时间需要 13 分钟。

2018-5-17重点补充

在我在自己的项目中尝试用下面的解决方案的时候,发现项目真的是“中毒太深”。在项目中添加扩展之后,发现有的UITextField文字可以垂直居中了,有的却还是不能。真是一脸懵逼啊!!!经过逐行对比代码发现以下重要规律:

当UITextField的clipsToBounds = YES或者 layer.masksToBounds = YES的时候,即使加上我下面的扩展也是没法解决问题的,文字还是无法垂直居中。亲测,不将这两个属性设置为YES的同时,添加该扩展可以解决问题。

当UITextField的clipsToBounds = YES或者 layer.masksToBounds = YES的时候输入文字超长时文字不会超过文本框的范围。而设置为NO的话,输入超长文本的时候的效果如微信和淘宝的搜索框,输入过程中会有个超出文本框范围的动画,不过这个效果比文本不垂直居中的效果更容易让人接受。


最近发现UITextField在iOS 10下输入中文的过程中,文字显示会“掉下去”或者“文字下沉”,也不知道该怎么描述了(就是UITextField文字没有垂直居中),正好我的手机还是iOS 10的系统,一图胜千言,下面上效果:

简书.png

美团.png

优酷.png

我们看到,简书APP、美团APP和优酷APP都有这种问题,除此之外还有很多APP有这种情况就不一一列举了,当然还有我们自己的APP?。

经测试,iOS9和iOS 11没有这种问题,再加上网上搜了一下基本确定是iOS 10的bug,但奇怪的是iPhone自带的APP里面的UITextField竟然没有这种问题,苹果爸爸可真是坑得一逼啊?。

先让我们看看到底是什么在捣鬼,先通过Debug View Hierarchy来看下UITextField在输入状态下,视图层级是怎么样的:

UITextField效果.png

通过上图我们可以看到UITextField在输入状态下,上面有一个UIFieldEditor视图,它是一个UIScrollView的子类。(这里补充一下,UITextField在未输入状态时也就是键盘收起时它上面有一个UITextFieldLabel用来展示内容。在输入状态时它上面会有一个UIFieldEditor视图,可以左右滚动。)我们还看到这个UIFieldEditor的_UIFiedEditorContentView在垂直方向上和UITextField发生了一点点错位,问题就出在这里。

我们来看下不同系统下,这个UIFieldEditor的差异在哪里:

//iOS9 中文
;layer =
; contentOffset: {7902, 0}; contentSize: {8155, 28}>//iOS 11 中文
; layer =
; contentOffset: {6840, 0}; contentSize: {7101, 36.5}; adjustedContentInset: {0, 0, 0, 0}>//iOS 10 全英文
; layer =
; contentOffset: {1404.5, 0}; contentSize: {1686, 28}>//iOS 10 中文
; layer =
; contentOffset: {620, -3}; contentSize: {846, 28}>

注意观察contentOffset属性,在iOS 9和iOS 11以及iOS 10输入全英文字符时contentOffset.y = 0,而在iOS 10输入全中文时contentOffset.y = -3,是不是有种日了狗的感觉?

到此,问题的根源算是找到了,那怎么比较合理地解决这个bug呢?如果你曾经遇到过这个问题并且在网络上搜索过解决方案,你或许会搜索下面的解决方案:

//重写UITextField,然后重写以下方法:- (CGRect)textRectForBounds:(CGRect)bounds {    return CGRectInset(bounds, 2, 1);}- (CGRect)editingRectForBounds:(CGRect)bounds {    return CGRectInset(bounds, 2, 1);}

这种方式可能会让文字下沉效果不是那么明显,但是这些数字从哪来的呢,没有任何理论和数据支撑啊,就这样粗糙的解决难免会留下坑。而且提到UITextField的bug,我们肯定会想到UISearchBar吧?我们看下UISearchBar的效果:

UISearchBar效果.png

同样的问题啊!毕竟UISearchBar上面放着一个UITextField,而且如果我们用到UISearchDisplayController或者UISearchController,那我们是不是也要挨个改一遍呢?

显然这种方式是不可取的,这时候我们就需要利用runtime了。我们只需要利用runtime交换掉UITextField的layoutSubViews方法,在交换后的方法里面通过遍历子视图拿到这个UIFieldEditor,然后强行把它的contentOffset.y改成0就可以了。因为我们发现在iOS9和iOS 11以及iOS 10输入全英文字符状态下它显示正常时就是contentOffset.y = 0,这是有理论和数据支撑的。然后,考虑到这个问题是针对iOS 10系统下的,避免对其他系统或者新系统(比如系统哪天升级到iOS 12,系统对UITextField进行了重构)造成潜在影响,我们可以保守一点,只针对iOS 10系统时交换方法。

代码如下:

////  UITextField+Fix.m//  ////  Created by 简书Code_Ninja//  Copyright https://github.com/lqcjdx//#import "UITextField+Fix.h"#import 
@implementation UITextField (Fix)void swizzleMethod(Class class,SEL originalSelector,SEL swizzledSelector){ Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if(didAddMethod){ class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); }else{ method_exchangeImplementations(originalMethod, swizzledMethod); }}+ (void)load{ CGFloat systemVersion = [[UIDevice currentDevice].systemVersion floatValue]; if(systemVersion >= 10.0 && systemVersion < 11.0){ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; swizzleMethod(class, @selector(layoutSubviews), @selector(yl_layoutSubviews)); }); }}- (void)yl_layoutSubviews{ [self yl_layoutSubviews]; for(UIScrollView *view in self.subviews){ if([view isKindOfClass:[UIScrollView class]]){ CGPoint offset = view.contentOffset; if(offset.y != 0) { offset.y = 0; view.contentOffset = offset; } break; } }}@end

这样的好处是非常方便,无需修改已有代码,只需在项目中新建一个UITextField分类就可以一键修复UITextField、UISearchBar、UISearchDisplayController、UISearchController的输入中文时文字下沉的问题。

修改后的效果:

修改后的效果.png

好了,就写到这里了,看完记得去你的项目中看看在iOS 10系统下有没有这个问题哦。如果你有其他解决方案欢迎留言。

转载地址:http://zqnsa.baihongyu.com/

你可能感兴趣的文章
线上应用故障排查之二:高内存占用
查看>>
第四次作业
查看>>
异常处理汇总 ~ 修正果带着你的Code飞奔吧!
查看>>
BFS --- 素数环
查看>>
PCIE_DMA:xapp1052学习笔记
查看>>
python ----字符串基础练习题30道
查看>>
uva-10879-因数分解
查看>>
python 调用aiohttp
查看>>
Spring Boot中使用MyBatis注解配置详解
查看>>
linux下文件的一些文件颜色的含义
查看>>
跨域iframe高度自适应(兼容IE/FF/OP/Chrome)
查看>>
如何花更少的时间学习更多的知识
查看>>
学习鸟哥的Linux私房菜笔记(8)——文件查找与文件管理2
查看>>
升级fedora 18到fedora 19
查看>>
【代码小记】无
查看>>
BarTender 2016表单中的“秤显示”控件
查看>>
11月20日学习内容整理:jquery插件
查看>>
Redis客户端集群
查看>>
javascript基础篇:函数
查看>>
SVN与TortoiseSVN实战:补丁详解
查看>>