如何测试键盘是不是覆盖 UITableView 中的 UITextField?
Posted
技术标签:
【中文标题】如何测试键盘是不是覆盖 UITableView 中的 UITextField?【英文标题】:How to test if keyboard is covering UITextField in UITableView?如何测试键盘是否覆盖 UITableView 中的 UITextField? 【发布时间】:2013-10-06 16:26:20 【问题描述】:我如何检查键盘是否覆盖了UIScrollView
内的第一响应者(可能是UITableView
,也可能不是UITableView
)?请注意,UIScrollView
不一定会覆盖整个 viewController 的视图,可能会包含在模态视图中 (UIModalPresentationFormSheet
)。
我正在使用来自Apple's reference documentation and example 的修改后的代码,但是即使键盘明显覆盖了第一响应者,CGRectContainsPoint
也会返回 false。很明显我没有正确使用convertRect:toView
。
另外,Apple 的代码没有考虑到视图不是全屏的,因此将 scrollView 的 contentInset 设置为键盘的全高并不是一个很好的解决方案——它应该只插入到覆盖 firstResponder 的键盘。
- (void)keyboardWasShown:(NSNotification*)aNotification
// self.scrollView can be a tableView or not. need to handle both
UIView *firstResponderView = [self.scrollView findFirstResponder];
if (!firstResponderView)
return;
NSDictionary* info = [aNotification userInfo];
CGRect rect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
// convertRect:toView? convertRect:fromView? Always confusing
CGRect kbRect = [self.scrollView convertRect:rect toView:nil];
CGRect viewRect = [self.scrollView convertRect:firstResponderView.bounds toView:nil];
// doesn't work. convertRect misuse is certainly to blame
if (!CGRectContainsPoint(kbRect, firstResponderView.frame.origin))
return;
// Only inset to the portion which the keyboard covers?
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbRect.size.height, 0.0);
self.scrollView.contentInset = contentInsets;
self.scrollView.scrollIndicatorInsets = contentInsets;
【问题讨论】:
附带说明:这也不是您可能想做的事情:[self.scrollView convertRect:firstResponderView.bounds toView:nil]
。 firstResponderView.bounds
不在滚动视图坐标中,而是在 firstResponderView
的局部坐标系中。您可能想在此处使用框架(在 superview 的 CS 中。
【参考方案1】:
没有进一步测试或深入了解逻辑,这行似乎很奇怪:
CGRect kbRect = [self.scrollView convertRect:rect toView:nil];
键盘矩形(包含在通知中)位于 window 坐标中,您可能希望将其转换为滚动视图坐标系。 [viewA convertRect:rect toView:viewB]
将 rect 从 viewA 的坐标系转换为 viewB 的坐标系,因此您实际上所做的与您应该做的相反(正如您所怀疑的那样)。
我通常做的是这样的:
- (void)keyboardWillShow:(NSNotification *)aNotification
NSDictionary *info = [aNotification userInfo];
CGRect kbRect = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
kbRect = [self.view.window convertRect:kbRect toView:self.view]; // convert to local coordinate system, otherwise it is in window coordinates and does not consider interface orientation
_keyboardSize = kbRect.size; // store for later use
[UIView animateWithDuration:0.25 animations:^
UIEdgeInsets insets = UIEdgeInsetsMake(0.0f, 0.0f, MAX(0.0f, CGRectGetMaxY(_tableView.frame) - CGRectGetMinY(kbRect)), 0.0f); // NB: _tableView is a direct subview of self.view, thus _tableView.frame and kbRect are in the same coordinate system
_tableView.contentInset = insets;
_tableView.scrollIndicatorInsets = insets;
[self scrollToActiveTextField]; // here I adapt the content offset to ensure that the active text field is fully visible
];
【讨论】:
刚刚注意到我的方法实际上完全解决了您的问题(“注意 UIScrollView 不一定会覆盖整个 viewController 的视图,并且可能包含在模态视图中”),因为我不只是盲目地使用键盘的高度以适应内容插入,但实际上考虑了滚动视图的框架,并且只适应键盘实际覆盖的增量。 我应该注意到self.view
不可用。键盘闪避由滚动视图管理器类处理,该管理器类通过滚动视图在初始化时进行管理,然后保存在弱引用中。用self.scrollView
替换self.view
有什么问题吗?
好吧,滚动视图坐标系实际上是受滚动影响的,所以可能不是一个好主意.. ;) 使用self.scrollView.superview
怎么样?
是的,只要它不是层次结构中的根视图,它就可以工作。
我还要注意,动画持续时间应该从信息字典中提取,而不是硬编码。以上是关于如何测试键盘是不是覆盖 UITableView 中的 UITextField?的主要内容,如果未能解决你的问题,请参考以下文章
使用 UISearchController 显示搜索结果和键盘覆盖 UITableView 中的底部行/部分
UITableView 键盘覆盖UITableViewCell的输入框解决方法(swift)