经过大量的试验和错误,我放弃了,并提出了这个问题。我见过很多人有类似的问题,但不能得到所有的答案工作正确。
我有一个由自定义单元格组成的UITableView。单元格由相邻的5个文本字段组成(有点像网格)。
当我试图滚动和编辑UITableView底部的单元格时,我不能设法让我的单元格正确地定位在键盘上方。
我看到过很多关于改变视图大小的回答……但到目前为止,没有一种效果很好。
谁能用一个具体的代码示例来阐明这样做的“正确”方式?
经过大量的试验和错误,我放弃了,并提出了这个问题。我见过很多人有类似的问题,但不能得到所有的答案工作正确。
我有一个由自定义单元格组成的UITableView。单元格由相邻的5个文本字段组成(有点像网格)。
当我试图滚动和编辑UITableView底部的单元格时,我不能设法让我的单元格正确地定位在键盘上方。
我看到过很多关于改变视图大小的回答……但到目前为止,没有一种效果很好。
谁能用一个具体的代码示例来阐明这样做的“正确”方式?
当前回答
这个解决方案为我工作,请注意这一行
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
您可以更改160值以使其与您的工作相匹配
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = activeField.superview.frame;
bkgndRect.size.height += kbSize.height;
[activeField.superview setFrame:bkgndRect];
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
tableView.contentInset = contentInsets;
tableView.scrollIndicatorInsets = contentInsets;
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = activeField.superview.frame;
//bkgndRect.size.height += kbSize.height;
[activeField.superview setFrame:bkgndRect];
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
}
其他回答
结合并填写几个答案(特别是Ortwin Gentz,用户98013)和另一篇文章中的空白,这将适用于iPad上的SDK 4.3的纵向或横向模式:
@implementation UIView (FindFirstResponder)
- (UIResponder *)findFirstResponder
{
if (self.isFirstResponder) {
return self;
}
for (UIView *subView in self.subviews) {
UIResponder *firstResponder = [subView findFirstResponder];
if (firstResponder != nil) {
return firstResponder;
}
}
return nil;
}
@end
@implementation MyViewController
- (UIResponder *)currentFirstResponder {
return [self.view findFirstResponder];
}
- (IBAction)editingEnded:sender {
[sender resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
UITableViewCell *cell = (UITableViewCell*) [[textField superview] superview];
[_tableView scrollToRowAtIndexPath:[_tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void)keyboardWillShow:(NSNotification*)notification {
if ([self currentFirstResponder] != nil) {
NSDictionary* userInfo = [notification userInfo];
// we don't use SDK constants here to be universally compatible with all SDKs ≥ 3.0
NSValue* keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardBoundsUserInfoKey"];
if (!keyboardFrameValue) {
keyboardFrameValue = [userInfo objectForKey:@"UIKeyboardFrameEndUserInfoKey"];
}
// Reduce the tableView height by the part of the keyboard that actually covers the tableView
CGRect windowRect = [[UIApplication sharedApplication] keyWindow].bounds;
CGRect viewRectAbsolute = [_tableView convertRect:_tableView.bounds toView:[[UIApplication sharedApplication] keyWindow]];
CGRect frame = _tableView.frame;
if (UIInterfaceOrientationLandscapeLeft == self.interfaceOrientation ||UIInterfaceOrientationLandscapeRight == self.interfaceOrientation ) {
windowRect = CGRectMake(windowRect.origin.y, windowRect.origin.x, windowRect.size.height, windowRect.size.width);
viewRectAbsolute = CGRectMake(viewRectAbsolute.origin.y, viewRectAbsolute.origin.x, viewRectAbsolute.size.height, viewRectAbsolute.size.width);
}
frame.size.height -= [keyboardFrameValue CGRectValue].size.height - CGRectGetMaxY(windowRect) + CGRectGetMaxY(viewRectAbsolute);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_tableView.frame = frame;
[UIView commitAnimations];
UITableViewCell *textFieldCell = (id)((UITextField *)self.currentFirstResponder).superview.superview;
NSIndexPath *textFieldIndexPath = [_tableView indexPathForCell:textFieldCell];
// iOS 3 sends hide and show notifications right after each other
// when switching between textFields, so cancel -scrollToOldPosition requests
[NSObject cancelPreviousPerformRequestsWithTarget:self];
_topmostRowBeforeKeyboardWasShown = [[_tableView indexPathsForVisibleRows] objectAtIndex:0];
[_tableView scrollToRowAtIndexPath:textFieldIndexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
}
- (void) scrollToOldPosition {
[_tableView scrollToRowAtIndexPath:_topmostRowBeforeKeyboardWasShown atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
- (void)keyboardWillHide:(NSNotification*)notification {
if ([self currentFirstResponder] != nil) {
NSDictionary* userInfo = [notification userInfo];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
_tableView.frame = self.view.bounds;
[UIView commitAnimations];
[self performSelector:@selector(scrollToOldPosition) withObject:nil afterDelay:0.1];
}
}
@end
因为你在一个表格中有文本字段,最好的方法是调整表格的大小——你需要设置tableView.frame的高度比键盘的大小小(我认为大约165像素),然后当键盘被关闭时再次展开它。
如果你不想让用户滚动,你也可以选择在那个时候禁用tableView的用户交互。
基于bartjomiej semazynk解决方案的Swift 3最简单的解决方案:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(CreateEditRitualViewController.keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: Keyboard Notifications
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
@objc func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.2, animations: {
// For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
})
}
一个更加流线型的解决方案。它滑入UITextField委托方法,所以它不需要搞砸/ UIKeyboard通知。
实现注意事项:
kSettingsRowHeight——UITableViewCell的高度。
offsetTarget和offsetThreshold基于kSettingsRowHeight。如果使用不同的行高,则将这些值设置为point的y属性。[alt:以不同的方式计算行偏移量。]
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
CGFloat offsetTarget = 113.0f; // 3rd row
CGFloat offsetThreshold = 248.0f; // 6th row (i.e. 2nd-to-last row)
CGPoint point = [self.tableView convertPoint:CGPointZero fromView:textField];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
CGRect frame = self.tableView.frame;
if (point.y > offsetThreshold) {
self.tableView.frame = CGRectMake(0.0f,
offsetTarget - point.y + kSettingsRowHeight,
frame.size.width,
frame.size.height);
} else if (point.y > offsetTarget) {
self.tableView.frame = CGRectMake(0.0f,
offsetTarget - point.y,
frame.size.width,
frame.size.height);
} else {
self.tableView.frame = CGRectMake(0.0f,
0.0f,
frame.size.width,
frame.size.height);
}
[UIView commitAnimations];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
CGRect frame = self.tableView.frame;
self.tableView.frame = CGRectMake(0.0f,
0.0f,
frame.size.width,
frame.size.height);
[UIView commitAnimations];
return YES;
}
这个解决方案为我工作,请注意这一行
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
您可以更改160值以使其与您的工作相匹配
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = activeField.superview.frame;
bkgndRect.size.height += kbSize.height;
[activeField.superview setFrame:bkgndRect];
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height+160) animated:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeField = textField;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
activeField = nil;
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
tableView.contentInset = contentInsets;
tableView.scrollIndicatorInsets = contentInsets;
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect bkgndRect = activeField.superview.frame;
//bkgndRect.size.height += kbSize.height;
[activeField.superview setFrame:bkgndRect];
[tableView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES];
}