前言
现就职于一家拥有菜谱分享功能的App的公司,某tableView页面,有着相当多的textview和textfield,点击输入框时需要进行键盘的弹出处理,并自动滚动到相应的位置。试了一些网上分享的方法,觉得都不是很好,所以结合苹果官方文档,自己总结了一下。
正题
1、最容易存在的问题
在键盘处理的过程中,最容易出现问题的就是,在键盘监听事件中,tableView的frame的修改,网上分享的大部分都是修改frame,这样会导致tableView的cell被遮挡,可能引起获取不到cell的indexPath,导致无法滚动到指定位置
还有一点就是UITableViewController的使用,如果直接使用UITableViewController,键盘弹出事件是不用我们开发者去处理的,UITableViewController自动帮我们实现了,也就是点击cell中的输入框,就可以直接弹出到可见区域,进行编辑。但UITableViewController的view是一个tableView,也就是说,你想在这个controller里加一个固定位置的view,是不可能的,这就牺牲了页面的可定制性
2、如何去实现
- (void)registerForKeyboardNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)aNotification {
NSDictionary* info = [aNotification userInfo];
// 注意不要用UIKeyboardFrameBeginUserInfoKey,第三方键盘可能会存在高度不准,相差40高度的问题
CGSize kbSize = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
// 修改滚动天和tableView的contentInset
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, kbSize.height, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, kbSize.height, 0);
// 跳转到当前点击的输入框所在的cell
[UIView animateWithDuration:0.2 animations:^{
[self.tableView scrollToRowAtIndexPath:_indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
}];
}
- (void)keyboardWillBeHidden:(NSNotification *)aNotification {
self.tableView.contentInset = UIEdgeInsetsZero;
self.tableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}
这里我们需要添加对键盘事件通知的检测,而对自己的tableView所做的改变,不是frame,而是contentInset,这样就可以保证tableView的滚动范围为键盘上方的区域,可见区域为整个屏幕。
_indexPath全局变量,需要在textfield的代理中去获取,获取到正在编辑的输入框所在的cell。
- (void)textFieldDidBeginEditing:(UITextField *)textField {
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)textField.superview.superview];
_indexPath = indexPath;
}
3、疑难问题
iOS8之后开始,iOS系统开始支持第三方输入法了,在第三方键盘弹出的时候,
UIKeyboardWillShowNotification会有三次通知,
- (void)keyboardWillShow:(NSNotification *)aNotification
方法会执行三次,而三次的键盘高度可能是不一样的,以最后一次高度为准,所以tableView在滚动的时候,默认的动画在多次执行时,可能会存在前一个动画没执行完成,后面的方法就不会执行,从而导致tableView无法滚动到目标位置的问题。
[self.tableView scrollToRowAtIndexPath:_indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
所以要改成如下的UIView动画,就OK了
[UIView animateWithDuration:0.2 animations:^{
[self.tableView scrollToRowAtIndexPath:_indexPath atScrollPosition:UITableViewScrollPositionTop animated:NO];
}];
而掌握了以上窍门后,那tableView和scrollView想滚动到指定位置,就很简单了。