打造更好的iOS文本输入体验
做客户端开发,不可避免的需要和文本输入打交道。今天我们来聊聊,如何在iOS里面打造更好的文本输入体验。
全文包含4部分内容:
1. 处理键盘遮挡视图问题
2. 动态高度的输入框
3. 记住用户选择的键盘
4. 自定义键盘
处理键盘遮挡视图问题
我们都知道,键盘有不同的尺寸,不同语言的键盘或不同设置的键盘,尺寸都会不同。比如纯英文键盘和汉字九宫格键盘高度就不一样,更不用说还有其他不同高度的第三方键盘呢。
而处理键盘遮挡视图问题,首先需要得到键盘的高度。iOS中有几个和键盘相关的通知:
|
这些通知的userInfo
里面都包含一个叫UIKeyboardFrameEndUserInfoKey
的key。我们注册这些通知,就可以从通知中获得键盘的frame
信息:
|
获得frame
后,并不能立即使用。因为键盘都是全屏的,它的frame
总是处于屏幕坐标系当中的。我们需要将键盘的frame
转化到我们的视图坐标系当中:
|
然后再计算出,键盘和我们的视图之间的重叠高度:
|
之后再调节我们的布局约束,把被遮挡内容往上移,即可避免键盘遮挡我们的视图内容。例如:
|
当然,如果视图是scrollView,也可以调整scrollView的contentInset
和contentOffset
,解决遮挡。
通常,在处理键盘遮挡问题时,我们都会让界面跟随着键盘动画一起移动。然而我们自己做的动画,可能会遇到和键盘动画不同步的问题。这个问题,这篇文章有讨论。正确的做法是:从userInfo
中取出键盘动画的duration
和curve
来使用。
不过,现在通常都不需要自己处理键盘遮挡问题。原生的UITableViewController会自动调整contentInset
,并且如果需要也会自动滚动内容,以避免键盘遮挡问题。此外,也有很多专门处理键盘交互的开源库,比如 TPKeyboardAvoiding 就是其中一个比较优秀的库,也是我经常使用的库,在此推荐给大家。它代码入侵少,不需要写任何配置或初始化代码,仅需将界面上使用的scrollView、tableView 或 collectionView 的类替换为TPKeyboardAvoiding对应类即可。剩下的“键盘遮挡”、“点击空白区域隐藏键盘”、“点击键盘Next按钮自动跳到下一个输入框”等问题就交给它处理。
动态高度的输入框
动态高度的输入框,也很常见,比如微信聊天界面的输入框,高度就会随输入内容动态增长。实现这个需求,其实并不复杂。
首先,禁用textView的scrollable
属性:
|
禁用scrollable
属性之后,可以直接用textView的sizeThatFits
方法,计算内容高度:
|
如果要限制最大高度,增加一个高度约束即可:
|
记住用户选择的键盘
在使用多语言的用户中,会遇到这样一个问题。例如,和朋友A聊天用的是中文,和朋友B聊天用的是英文,这样就会需要在两种键盘之间不停地切换。
在iOS的「信息」应用中有个小细节,就是当我和朋友A聊天时,应用知道我使用的是中文键盘;而当我和朋友B聊天时,应用知道我使用的是英文键盘。在键盘弹出时,自动弹出对应语言的键盘。
这是如何做到的?
原来是iOS系统提供一个被称作“文本输入上下文标示符”的标示符,可以将它和任何一个UIResponder关联起来。当系统发现我们将一个标示符和某个UIResponder关联起来后,它都会把标示符自动跟用户选择的键盘关联起来,并保存到user default中。下次,当这个UIResponder成为第一响应者(FirstResponder)的时候,对应的键盘就会被自动检索出来。
我们唯一要做的是找一个好一点的标示符。标示符需要具有唯一性,不要重复。比如说,用户ID、对话ID、群组ID,这些都是很好的标示符。
|
自定义键盘
创建自定义键盘,首先要继承UIInputViewController
,然后在其提供的inputView
上加入自定义的键盘界面控件。响应用户的输入事件,主要依靠textDocumentProxy
属性进行。比如,可以通过textDocumentProxy
属性向光标位置插入文本、或删除光标前面的文本。下图展示了键盘运行过程中一些重要的对象,以及它们在开发流程中的位置。
我们开发的自定义键盘,如果只在自己的应用内部使用,只需将inputView
传递给输入框或响应者对象:
|
如果自定义键盘,要在整个系统中使用,则需要创建一个自定义键盘扩展。
创建自定义键盘扩展非常简单,如果你已经实现了一个UIInputViewController
子类,你都不需要修改任何代码,仅需要:
- 在项目里面新建一个「Custom Keyboard Extension」类型的target
- 将已经实现的
UIInputViewController
子类加入target - 将自定义键盘需要的图片等资源加入target
- 将target的Info.plist中 NSExtension - NSExtensionPrincipalClass 键值中的类名改为你的自定义
UIInputViewController
子类名
然后,用户只要在设置里面开启键盘,就可以在系统的任何地方使用。
全文完!
参考:
WWDC 2017 - Session 242 - The Keys to a Better Text Input Experience
UIWindow Reference
iOS 7 键盘动画
App Extension Programming Guide - Custom Keyboard
UIInputViewController Class Reference