填坑使人进步之 ------- UITextView的复制粘贴

96
Wilson魏
2016.10.22 02:43* 字数 1875

定场诗

道德三皇五帝,功名夏侯商周;五霸七雄闹春秋,顷刻兴亡过手!青史几行名姓,北邙无数荒丘;前人埋坑后填,说不尽的苦涩难言.

前言

     我们怀揣青春,码下一行行的变量.我们憧憬人生,写下一段段函数.我们拥抱着梦想,敲出一曲曲方法.我们弯着腰幻想着自己可能是指尖程序世界的造物主,我们驼着背笑看着键盘上飞舞着的似乎是跳跃的精灵,我们卯足了劲儿只为了自己创造的不仅仅是代码更是艺术品.然而我们却一次次被绊倒在了坑下,泥泞不堪,愈撕扯愈浑浊.

前言就是瞎扯淡

拿出了小学生作文(低年级版)的水平写了个前言抒发一下自己寂寥~寂寥~的心情,打算从今天开始开一个系列(手动不要脸)和大家分享一下自己遇到的听到的那些在 iOS 开发中的那些坑与解决方案. 括弧,扯淡为主代码为辅,生活甚是百般苛刻,人生真的需要笑对....

我知道,很累的

主题和背景

今天要分享的是一个关于 UITextView 的坑,这个坑其实说大不小,说小也不小,至少看起挺严重.改这个 bug 你得有过日子的心.至少其中一个的坑是我在厕所释放内存的时候想到的解决方案.

背景是我们这个工程中关于 textView 的使用中,有一个复制粘贴大段文字出现的一个bug,这个 bug 主要是出现在环信的文字输入框中.

bug1:  当我复制了大段的问题,这个所自适应的文本高度已经超过了 textView 所设定的最大自适应高度时,就会这样:


复制粘贴来的文字不见了

但是当你的小手指轻轻的抚摸滑动他一下,文字就全滚动下来了...就像这样


小手一划


bug2:当我复制粘贴来的文字并没有那么多,刚好够触发了刚好超过了 textView 的最小高度,又小于最大高度,这个时候,由于 textView.contentSize.height 是小于 textView 的 frame 高度的,又不会触发滚动,就成了这个鬼样子:

这样内容就被遮挡住了一部分,动又动不了

当然,如果你再输入些字,只要触发了文本的自适应高度变化了,就会正常显示了


心酸的 Fix 之路

本来在这个 bug 会报出来之初呢,我还是很懵逼的,因为之前也用过环信,也自己写过 textView, 从来都没发现这样的问题,而且实际上,在另一个功能点上也报出来类似bug1的那种问题,我知道,这个问题肯定出现在某些角落中,但是当时任务缠身,工期短,任务重,代码早已经被前面的开发人员搞的千疮百孔,任务需求也是零散琐碎,重写来不及,迭代更是心力交瘁,如果你有代码洁癖,来读读我们的源码,分分钟治好你!所以这个问题就一直在延后.

解决 Bug1

直到前几天,我们的两个客户端终于有了相对稳定一些的版本,大问题也修的差不多了,我终于有了一些精力来思考一下这些严重的小问题,于是在一个刚刚解决了一个大bug的下午,我决定去厕所 release 一些占用内存许久的 bian 量, 在整洁的隔间,和尚存余温的圈圈上,我开始陷入了沉思,环信在底层用的是系统的 UITextView,我在另一个功能点也用的是 UITextView,在谷歌上百度了一大圈也没发现有人跟我遇到一样的问题啊,我自己单开了一个 demo 写了一简单的 textView 也没这个问题啊?那既然不是原生控件的 bug, 到底有哪些代码会不需要写代码就可以改变全局的控件呢?

卧槽!垂死病中惊坐起!忽然想起来之前有个孩儿为了不用手动写 TextView 的随键盘滚动,曾经集成过一个第三方,叫 IQKeyboardManager,  会不会是因为这个???急忙离开温暖的圈圈,坐在电脑前机智的 cmd + shift + o 

卧槽还真有

去 delegate 中, 洋洋洒洒的写到:

[IQKeyboardManager sharedManager].shouldFixTextViewClip = NO;[IQKeyboardManager sharedManager].canAdjustTextView = NO;

cmd + R, 复制, 粘贴, 显示正常,点击解决,机智如我,开始和 iOS 小伙伴 Jack 吹比去

但此时的我,并没有意识到,真正的危机才刚刚开始

ps: IQKeyboardManager 的确可以省去很多关于键盘滚动的处理,并且还能带来一些 toolBar,但是挺鸡肋的其实,并且会对很多已经写好的功能造成影响,所以删掉,或全局禁用就好了.

Bug2

然而, bug2 并没有解决,当我复制了没有那么多问题的时候,提测,被打回,我发现, bug2 依然没有解决, 加上产品提的 bug 需求上说,复制粘贴了文字后就不能动,要可以滚动才行,只是我就将焦点放在了 contentSize. 并没有在代码逻辑中发现任何问题.但是注意到了环信 UI 中有一段代码:

else 中处理新的 containSize 高度有变化并没有超过阈值时的处理逻辑 注意看setContentOffSet!!!

self.version 是系统版本,当设备的系统版本小于7.0 中间textView 的 setContentOffSet ,后面跟的是 point, 这是设置 content 坐标偏移量的代码,点进去看,并没有发现苹果 API 弃用了这个方法,但问题是当系统版大于等于7.0的情况完全没有做任何处理. 搜一下其他用到系统版本的地方,发现在获取 tableview 高度的地方是这样设置的

通过 siztThatFits 来获取适配最佳 size

由于 UITextView 继承了 scrollview ,他的滚动也是通过 containSize 和 size 进行比对,只有 containSize 大于 size 才可以触发滚动,不可以滚动是正常的,但是从现象上看像是向上偏移了,于是打开模拟器,勾选Color Blended Layers 模式,发现

textView 的整个 contain 似乎被向上偏移了

进一步调试,进到 View Hierarchy 中瞅瞅看

感觉像是被截掉了

深入调试:


做好对应
并没有被截掉,这里显示了完成的 containerView 和文字

这样经过调试终于发现, containerView 和文字,并没有被截掉,而是坐标偏移量上移了,并在 visible 层被遮挡.

所以,在环信代码中用于7.0以下的方法,设置containOffSet是有用的,环信的代码逻辑不严谨,但是为了不破坏环信的整体代码结构,也为了避免出现其他问题而打脸,我采用了一种机智的办法:

补全代码逻辑通过代码将 textView 的内容滚动下来显示完全

妥了,完美解决~~~~~周一和环信客服撕逼去咯~~~~~~

最后,通过一个小 Demo 模拟了一下复制粘贴的现象

通过三种方式进行的 textView 的高度自适应

我用三种方式发现依然是这样


依然如此

说明在苹果原生的方法中,面度大段的复制文字,的确会造成 containerView 的偏移,解决方案就是,将视图滚到 visible层,或者将重新设置偏移量

scrollRangeToVisible

setContentOffset

收尾

我们在开发过程中总是会遇到这样或那样的坑,时不时的会在填坑和埋坑中周而复始,但是最终我们回过头来或许会发现,我们在填坑中不断成长.

/*

*

**你只有非常努力才能看起来毫不费力

*/


/******************   10 月 22 日 第一次更新 ******************************/

日记本
Gupao