获取UITableView滚动到选定的UITextField并避免被键盘隐藏

我在UIViewController (而不是UITableViewController )的表视图中有一个UITextField 。 如果表格视图位于UITableViewController ,则表格将自动滚动到正在编辑的textField字段,以防止其被键盘隐藏。 但在UIViewController它不。

我已经尝试了几天阅读通过多种方式来尝试完成这一点,我不能得到它的工作。 实际滚动的最接近的是:

 -(void) textFieldDidBeginEditing:(UITextField *)textField { // SUPPOSEDLY Scroll to the current text field CGRect textFieldRect = [textField frame]; [self.wordsTableView scrollRectToVisible:textFieldRect animated:YES]; } 

但是,这只能将表格滚动到最上面一行。 看起来像一个容易的任务是一两天的挫折。

我正在使用以下来构造tableView单元格:

 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]]; UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease]; cell.accessoryType = UITableViewCellAccessoryNone; UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)]; theTextField.adjustsFontSizeToFitWidth = YES; theTextField.textColor = [UIColor redColor]; theTextField.text = [textFieldArray objectAtIndex:indexPath.row]; theTextField.keyboardType = UIKeyboardTypeDefault; theTextField.returnKeyType = UIReturnKeyDone; theTextField.font = [UIFont boldSystemFontOfSize:14]; theTextField.backgroundColor = [UIColor whiteColor]; theTextField.autocorrectionType = UITextAutocorrectionTypeNo; theTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; theTextField.clearsOnBeginEditing = NO; theTextField.textAlignment = UITextAlignmentLeft; //theTextField.tag = 0; theTextField.tag=indexPath.row; theTextField.delegate = self; theTextField.clearButtonMode = UITextFieldViewModeWhileEditing; [theTextField setEnabled: YES]; [cell addSubview:theTextField]; [theTextField release]; } return cell; } 

我怀疑我可以得到的tableView正常滚动,如果我可以以某种方式传递indexPath.rowtextFieldDidBeginEditing方法?

任何帮助表示赞赏。

在我的应用程序中,我已经成功地使用了像这样的contentInsetscrollToRowAtIndexPath的组合:

当您想要显示键盘时,只需在底部添加一个具有所需高度的表的contentInset:

 tableView.contentInset = UIEdgeInsetsMake(0, 0, height, 0); 

那么,你可以安全地使用

 [tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:cell_index inSection:cell_section] animated:YES]; 

通过添加contentInset,即使您关注最后一个单元格,tableView仍然可以滚动。 只要确保在解散键盘时重置contentInset即可。

编辑:
如果只有一个部分(可以用0replacecell_section ),并使用cell_section标记来通知单元格行。

检查这个UITableView或UIScrollView滚动上面的键盘上的UITextField

 - (void)keyboardWillShow:(NSNotification *)sender { CGFloat height = [[sender.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height; NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{ UIEdgeInsets edgeInsets = UIEdgeInsetsMake(0, 0, height, 0); tableView.contentInset = edgeInsets; tableView.scrollIndicatorInsets = edgeInsets; }]; } - (void)keyboardWillHide:(NSNotification *)sender { NSTimeInterval duration = [[sender.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationOptions curveOption = [[sender.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16; [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState|curveOption animations:^{ UIEdgeInsets edgeInsets = UIEdgeInsetsZero; tableView.contentInset = edgeInsets; tableView.scrollIndicatorInsets = edgeInsets; }]; } 

并在 – (void)viewDidLoad

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 

然后

 - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } 

这是对FunkyKat的答案的一个调整(非常感谢FunkyKat!)。 为了将来的iOS兼容性,将UIEdgeInsetsZero硬编码可能是有益的。

相反,我要求当前插入值,并根据需要调整底部值。

 - (void)keyboardWillShow:(NSNotification *)sender { CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.height : kbSize.width; if (isIOS8()) height = kbSize.height; [UIView animateWithDuration:duration animations:^{ UIEdgeInsets edgeInsets = [[self tableView] contentInset]; edgeInsets.bottom = height; [[self tableView] setContentInset:edgeInsets]; edgeInsets = [[self tableView] scrollIndicatorInsets]; edgeInsets.bottom = height; [[self tableView] setScrollIndicatorInsets:edgeInsets]; }]; } - (void)keyboardWillHide:(NSNotification *)sender { NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; [UIView animateWithDuration:duration animations:^{ UIEdgeInsets edgeInsets = [[self tableView] contentInset]; edgeInsets.bottom = 0; [[self tableView] setContentInset:edgeInsets]; edgeInsets = [[self tableView] scrollIndicatorInsets]; edgeInsets.bottom = 0; [[self tableView] setScrollIndicatorInsets:edgeInsets]; }]; } 

为了解决这个问题,我在这里发布了必要的方法:

 - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *identifier = [NSString stringWithFormat: @"%d:%d", [indexPath indexAtPosition: 0], [indexPath indexAtPosition:1]]; UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:identifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease]; UITextField *theTextField = [[UITextField alloc] initWithFrame:CGRectMake(180, 10, 130, 25)]; theTextField.keyboardType = UIKeyboardTypeDefault; theTextField.returnKeyType = UIReturnKeyDone; theTextField.clearsOnBeginEditing = NO; theTextField.textAlignment = UITextAlignmentLeft; // (The tag by indexPath.row is the critical part to identifying the appropriate // row in textFieldDidBeginEditing and textFieldShouldEndEditing below:) theTextField.tag=indexPath.row; theTextField.delegate = self; theTextField.clearButtonMode = UITextFieldViewModeWhileEditing; [theTextField setEnabled: YES]; [cell addSubview:theTextField]; [theTextField release]; } return cell; } -(void) textFieldDidBeginEditing:(UITextField *)textField { int z = textField.tag; if (z > 4) { // Only deal with the table row if the row index is 5 // or greater since the first five rows are already // visible above the keyboard // resize the UITableView to fit above the keyboard self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,200.0); // adjust the contentInset wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 10); // Scroll to the current text field [wordsTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:z inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; } } - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { // Determine which row is being edited int z = textField.tag; if (z > 4) { // resize the UITableView to the original size self.wordsTableView.frame = CGRectMake(0.0,44.0,320.0,416.0); // Undo the contentInset wordsTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); } return YES; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { // Dismisses the keyboard when the "Done" button is clicked [textField resignFirstResponder]; return YES; } 

试试我的编码,这将有助于ypu

 tabelview.contentInset = UIEdgeInsetsMake(0, 0, 210, 0); [tableview scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:your_indexnumber inSection:Your_section] atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; 

苹果有一个官方的post解释如何做到这一点,就像他们在UITableViewController中做的那样。 我的Stackoverflow答案有一个迅速的版本解释。

https://stackoverflow.com/a/31869898/1032179

我需要一个简单的解决scheme,所以帮助我:

 func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { let pointInTable = textField.superview!.convert(textField.frame.origin, to: tableView) var tableVContentOffset = tableView.contentOffset tableVContentOffset.y = pointInTable.y if let accessoryView = textField.inputAccessoryView { tableVContentOffset.y -= accessoryView.frame.size.height } tableView.setContentOffset(tableVContentOffset, animated: true) return true; } 

在这里输入图像说明

你需要调整tableView本身的大小,使它不会在键盘下。

 -(void) textFieldDidBeginEditing:(UITextField *)textField { // SUPPOSEDLY Scroll to the current text field self.worldsTableView.frame = CGRectMake(//make the tableView smaller; to only be in the area above the keyboard); CGRect textFieldRect = [textField frame]; [self.wordsTableView scrollRectToVisible:textFieldRect animated:YES]; } 

或者,您可以使用键盘通知; 这个工作稍微好一些,因为你有更多的信息,并且在知道键盘何时出现时更加一致:

 //ViewDidLoad [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; 

然后执行:

 - (void)keyboardWillShow:(NSNotification *)notification { } - (void)keyboardWillHide:(NSNotification *)notification { } 

我的代码。 也许有人会有用:在tableView自定义textField单元格

.M

  @property (nonatomic, strong) UITextField *currentCellTextField; CustomCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2]; if (cell == nil) { NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil]; cell = (CustomCell *)[nib objectAtIndex:0]; cell.textfield.delegate = self; } - (void) textFieldDidBeginEditing:(UITextField *)textField { self.currentCellTextField = textField; CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField]; NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt]; if (path.section >= 2) { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; self.organisationTableView.contentInset = UIEdgeInsetsMake(0, 0, kOFFSET_FOR_KEYBOARD, 0); CGPoint siize = self.organisationTableView.contentOffset; siize.y =(pnt.y-170); self.organisationTableView.contentOffset = CGPointMake(0, siize.y); [UIView commitAnimations]; } } -(BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; CGPoint pnt = [self.organisationTableView convertPoint:textField.bounds.origin fromView:textField]; NSIndexPath* path = [self.organisationTableView indexPathForRowAtPoint:pnt]; if (path.section >= 2) { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; self.organisationTableView.contentInset = UIEdgeInsetsZero; self.organisationTableView.contentOffset = CGPointMake(0, self.organisationTableView.contentOffset.y); [UIView commitAnimations]; } return YES; } 

在我的情况下,我的UITableview是在另一个UIView中,而UIvie是在主UIScrollview中。 所以我对这类问题使用了更多的通用解决scheme。 我只是在特定的UIScrollView中find了我的单元格的Y坐标,然后滚动到正确的点:

 -(void)textFieldDidBeginEditing:(UITextField *)textField{ float kbHeight = 216;//Hard Coded and will not support lanscape mode UITableViewCell *cell = (UITableViewCell *)[textField superview]; float scrollToHeight = [self FindCordinate:cell]; [(UIScrollView *)self.view setContentOffset:CGPointMake(0, scrollToHeight - kbHeight + cell.frame.size.height) animated:YES]; } -(float)FindCordinate:(UIView *)cell{ float Ycordinate = 0.0; while ([cell superview] != self.view) { Ycordinate += cell.frame.origin.y; cell = [cell superview]; } Ycordinate += cell.frame.origin.y; return Ycordinate; } 

另一个简单的解决scheme是为最后一个表格部分的页脚添加一个额外的空间:

 - (float)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { if (section == lastSection) { return keyboard height; } return 0; } 

我们也可以将我们的图标添加到这个区域。 🙂

你可以尝试添加一个UITableViewController到UIViewController而不是一个表视图。 这样,你可以调用UITableViewController的viewWillAppear,一切都将显示工作。

例:

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [tableViewController viewWillAppear:animated]; } 

我给@FunkyKat和@bmauter答案增加了一个小function(顺便说一句,应该是接受的答案)

在键盘显示之前/之后,常规的表格视图边缘插入被保留。

 - (void)keyboardWillShow:(NSNotification *)sender { CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height; [UIView animateWithDuration:duration animations:^{ UIEdgeInsets edgeInsets = self.tableView.contentInset; edgeInsets.bottom += height; self.tableView.contentInset = edgeInsets; edgeInsets = self.tableView.scrollIndicatorInsets; edgeInsets.bottom += height; self.tableView.scrollIndicatorInsets = edgeInsets; }]; } - (void)keyboardWillHide:(NSNotification *)sender { CGSize kbSize = [[[sender userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; NSTimeInterval duration = [[[sender userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; CGFloat height = UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? kbSize.width : kbSize.height; [UIView animateWithDuration:duration animations:^{ UIEdgeInsets edgeInsets = self.tableView.contentInset; edgeInsets.bottom -= height; self.tableView.contentInset = edgeInsets; edgeInsets = self.tableView.scrollIndicatorInsets; edgeInsets.bottom -= height; self.tableView.scrollIndicatorInsets = edgeInsets; }]; }