- 问题背景
自定义实现UIKeyboard的accessoryView的基本原理是根据UIKeyboard的frame来动态调整accessoryView的frame值,为了能达到accessoryView的平滑的变动,我们用UIView的类方法animateWithDuration:delay:options:animations:completion:来动态调整accessoryView的frame值
- 问题出现描述
我们根据通知UIKeyboardWillShowNotification来触发调用animateWithDuration:delay:options:animations:completion:,那么问题来了,当UITextField的属性autocorrectionType设置为UITextAutocorrectionTypeYes(也就是在中文系统下唤起键盘的时候会自动切换为中文键盘),并且在首次打开键盘的时候,系统会发送多次UIKeyboardWillShowNotification通知,从而会多次触发调用animateWithDuration:delay:options:animations:completion:,先来看看代码:
这段代码会被多次连续执行,照理对self.frame(self对应accessoryView)的改变只需在animations的block中处理即可,但是代码的原作者不知道出于什么目的在competion中也同样执行了一遍,来看一下NSLog中的内容:
关注下每次selfEndingRect的frame的y轴值,我们期望的最终值是276,但是看到completion中的selfEndingRect的frame的y轴值的顺序刚好相反,最终值为312,也就是第一次调用时候的值,导致accessoryView的最终展现的位置要比预期的偏下36
- 问题分析
一些无用的分析过程就不累述了,看看最终的结果分析就好,先来写一段测试代码,循环执行多次animate操作,每次动画执行时间为10秒
再来看一下log:
分析下不难发现,第0次animate操作的completion最后执行,也就是10秒动画执行的时间后,后面的4次animate直接被cancel了,从时间上也可以发现,animate的开始时间和completion的结束时间都是在大约47秒的时候,两者相差0.*秒的时间,远小于设置的10秒动画时间,这里比较奇怪的一点是既然被cancel了,但是finish的值为什么还是为YES
- 解决方法
就本例来说,去掉completion中对frame的赋值就可以了
一般来说不太会出现本例一样循环进行animate操作,如果要实现连续的动画,简单方法就是在completion继续执行animate,以保证下一个animation是在上一个完成的基础上执行的