iOS“信息”中输入框交互式弹回。
在设计以输入框(接受并显示文本输入)为主的App用户界面时,常见的模式是输入框自动移动(一直显示在屏幕上),输入框位于键盘的顶部并随着键盘的移动而移动。
Apple的“消息”是一个很好的例子,它的UI就属于上述模式。从iOS 7起,它还可以通过滚动消息内容交互式弹回键盘。
这种模式很常见(尤其是聊天类App),但很少有App运用地像Apple的“消息”这么好。众所周知效仿的例子有Facebook Messenger和WhatsApp。
这并不是什么了不得的事,但也并不简单
能够把键盘交互式弹回并不是什么了不得的事,这可能是大多数用户都不会注意到的小细节。但是,它的确增强了App的手感。
然而不幸的是,解决方案并不明朗。开发人员已经尝试了很多方案并取得了不同程度的成功。有几个相关的开源项目,相关的博文和相关的StackOverflow提问,提供了从简单到复杂的解决方案。
简而言之,实现输入框自动移动很简单。但交互式弹回键盘就复杂了。以下是一些流行聊天App的尝试:
Google Hangouts:交互式弹回,输入框移动,键盘覆盖在上面随之移动。缺陷:弹回时,键盘和输入框之间的有空隙。
Slack for iPad:不支持交互式弹回,不过它在iPhone上是支持的。
Telegram、Line、微信:不支持交互式弹回。
收集资料
在寻找解决方案时,我发现了一些博客详细介绍了一些非常有用的技术,这完成了我们的解决方案的大半:赋给UIViewController根视图的inputAccessoryView一个非空的值,并让它在加载时立即响应(first responder)。详情见此:https://robots.thoughtbot.com/input-accessorizing-uiviewcontroller和http://derpturkey.com/uitextfield-docked-like-ios-messenger/。
不管怎样,这至少说明了两点:
- 输入框是键盘的窗口的子视图。我们并不想这样,尤其是对聊天App。
- 输入框的宽度扩大了键盘的宽度。除了iPad上的拆分键盘。
酝酿解决方案
我们已经知道,赋给inputAccessoryView一个非空的值能达到我们想要的效果,但会出现一些警告。
那么,如果:
- 我们赋给inputAccessoryView一个不可见视图
- 同时为了得知键盘frame的变化(作为交互式弹回的结果),我们使用KVO(键值观察)观察不可见视图的父视图(即键盘)的bounds/center属性
汇总
解决方案设计
基于前面描述的想法,上图展示了解决方案的各关键部分。这里我们把不可见的视图称为“Pseudo Input Accessory View”。
- 该解决方案的核心是键盘跟踪器。它通过两个来源跟踪并存储键盘状态:键盘通知(UIKit keyboard notifications)和Pseudo Input Accessory View父视图边界/中心变化的回调。
- Pseudo Input Accessory View Coordinator管理Pseudo Input Accessory View的单例,同时提供了改变其高度的方法(为了满足输入框变宽的需要)。
- Pseudo Input Accessory View由其Coordinator创建和管理。它使用KVO跟踪父视图的bounds/center属性并向Coordinator报告。
在这基础上,App在任何时候可以通过键盘跟踪器的实例查询当前键盘的状态。并且通过跟踪器的委托回调实时更新键盘。
根据键盘当前的frame调整输入框的布局,这就是随着键盘“自动移动”。在跟踪器的委托回调里,我们只需要在必要时重新调整布局。
管用吗?
是的,我认为我们已经搞定它了!
实现自动移动输入框的 Pie for iPad
以上是一个Pie for iPad的demo,并实现了自动伸缩输入框。
开源解决方案
在Pie中,我们努力打造最好的工作交流体验。但除此之外,我们也爱回馈社区。因此,我们打包了上述的解决方案包括一个demo作为一个小的开源库。