iOS 软键盘弹出和隐藏
IOS 软键盘的行为是直接由开发者控制的,操作系统只提供很少的管理策略。这造成了很麻烦的问题:
- 关闭软键盘也需要编程。
- 软键盘造成的界面遮挡需要开发者处理。
当然也有一些好处。在Android中,靠输入法中按键只能提交字符,比如QQ只能先确定输入,再执行发送;而在IOS中,输入法是直接由开发者控制,IOS版QQ可以在软键盘中直接执行发送。
以下记录IOS软键盘编程中一些问题的解决方案。
关闭软键盘
IOS的软键盘在输入结束后不会自动关闭,而需要编程方式来手动关闭:
-
设置TextField的代理为当前对象。可以在Storyboard中将TextField拖动至ViewController,选择delegate。也可以使用编程方式:
- (void)viewDidLoad{ [super viewDidLoad]; // 设置代理(首先为textField创建Outlet) self.textField.delegate = self; }
-
在ViewController中添加事件处理函数:
- (BOOL)textFieldShouldReturn:(UITextField *)textField { // 激活文本框即可 [textField resignFirstResponder]; return YES; }
另外,我们也希望在用户点击界面其他部分时,软键盘自动关闭。
- 添加gestureRecognizer。在Storyboard中,从对象库将Tap手势拖动到ViewController
- 绑定gestureRecognizer。按Ctrl将画布拖动至gestureRecognizer,并选择gestureRecognizer。
- 添加action。按Ctrl将gestureRecognizer拖动至ViewController.h,并选择Action。
-
添加Action处理函数:
- (IBAction)Tap:(id)sender { [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]; }
界面重布局
考虑一个聊天页面,在软键盘出现时,会遮挡输入框。此时需要减小页面其他部分的高度,使得输入框上移。然而,在输入中文的过程中软键盘的高度还会发生变化。于是我们需要监听软键盘的大小变化。
重布局有两种做法,一种是改变View
的大小;一种是改变约束。不过都得用编程方式,因为键盘高度是动态的(可能有多重键盘)。本文采取后一种,参考文章: http://www.think-in-g.net/ghawk/blog/2012/09/practicing-auto-layout-an-example-of-keyboard-sensitive-layout/
-
设置
Constants
,并包含页面最下方元素与父元素底的间隔,将该间隔约束以Outlet
方式引入到工程中,命名为vsHeight
。 -
注册通知:
- (void)viewWillAppear:(BOOL)animated{ ... [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitKeyboardAnimations:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(commitKeyboardAnimations:) name:UIKeyboardDidHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated{ ... [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil]; }
-
在软键盘框更新时,更新约束并重新布局:
- (void)keyboardWillShow:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey]; NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = (UIViewAnimationCurve)[info objectForKey:UIKeyboardAnimationCurveUserInfoKey]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:duration]; [UIView setAnimationCurve:curve]; self.vsToolbar.constant = kbFrame.CGRectValue.size.height; [self.view layoutIfNeeded]; [self ScrollToBottom]; } - (void)keyboardWillHide:(NSNotification *)notification { NSDictionary *info = [notification userInfo]; NSTimeInterval duration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = (UIViewAnimationCurve)[info objectForKey:UIKeyboardAnimationCurveUserInfoKey]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:duration]; [UIView setAnimationCurve:curve]; self.vsToolbar.constant = 0; [self.view layoutIfNeeded]; [self ScrollToBottom]; }
-
在键盘布局完成时再提交动画(否则会偏快)。
- (void)commitKeyboardAnimations:(NSNotification *)notification { [UIView commitAnimations]; }
同时,如果有子界面也需要更新,同样在KeyboardWillShow
中进行设置。要注意的是,更新子界面时软键盘还没有出现,使用UIView.layoutIfNeeded
进行强制更新。例如,在软键盘出现时,要将聊天内容滚动到底部:
-(void)KeyboardWillChangeFrame: (NSNotification *)notification {
...
[self.tableView layoutIfNeeded]; // important! recompute size of tableview
[self ScrollToBottom];
}
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2014/05/25/input-method-ios.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。