xcode uitableview keyboard uitextfield

xcode - Obtenga UITableView para desplazarse al UITextField seleccionado y evitar ser ocultado por el teclado



keyboard (13)

Tengo un UITextField en una vista de tabla en un UIViewController (no en un UITableViewController ). Si la vista de tabla se encuentra en un UITableViewController , la tabla se desplazará automáticamente al textField está editando para evitar que el teclado lo oculte. Pero en un UIViewController no es así.

He intentado durante un par de días leer varias formas para intentar lograr esto y no puedo lograr que funcione. Lo más parecido que se desplaza es:

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

Sin embargo, esto solo desplaza la tabla a la fila superior. Lo que parece una tarea fácil ha sido un par de días de frustración.

Estoy usando lo siguiente para construir las celdas 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; }

Sospecho que puedo hacer que tableView se desplace correctamente si de alguna manera puedo pasar el indexPath.row en el método textFieldDidBeginEditing ?

Cualquier ayuda es apreciada.


Apple tiene una publicación oficial que explica cómo hacerlo de forma natural, como lo hacen en UITableViewController. Mi respuesta ha explicado esto junto con una versión rápida.

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


En mi aplicación, he utilizado con éxito una combinación de contentInset y scrollToRowAtIndexPath esta manera:

Cuando desee mostrar el teclado, simplemente agregue un contentInset en la parte inferior con su tabla con la altura deseada:

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

Entonces, puedes usar de forma segura

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

Al agregar el contentInset, incluso si se está enfocando en la última celda, TableView aún podrá desplazarse. Solo asegúrese de que cuando cierre el teclado, restablezca el contentInset.

EDITAR:
Si solo tiene una sección (puede reemplazar cell_section con 0) y usa la etiqueta textView para informar la fila de la celda.

Verifique esto para Desplazar UITextField arriba Teclado en UITableView O UIScrollView


En mi caso, mi UITableview estaba dentro de otra UIView y UIvie estaba en el UIScrollview principal. Entonces usé una solución más general para ese tipo de problemas. Simplemente encontré la coordenada Y de mi celda en el UIScrollView específico y luego me desplacé al punto correcto:

-(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; }


Este es un ajuste a la respuesta de FunkyKat (¡muchas gracias, FunkyKat!). Probablemente sería beneficioso no codificar UIEdgeInsetsZero para la futura compatibilidad de iOS.

En su lugar, solicito el valor de inserción actual y modifico el valor inferior según sea necesario.

- (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]; }]; }


He agregado una pequeña característica a @FunkyKat y @bmauter (respuesta excelente por cierto, debería ser la que se acepta)

Las inserciones de borde de vista de tabla regulares se conservan, antes / después de la aparición del teclado.

- (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; }]; }


Mi código. Tal vez alguien sea útil: celda textField personalizada en tableView

.metro

@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; }


Necesita cambiar el tamaño del TableView para que no pase por debajo del teclado.

-(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]; }

Alternativamente, puede usar una notificación de teclado; esto funciona un poco mejor porque tiene más información y es más consistente en términos de saber cuándo se acerca el teclado:

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

Y luego implementar:

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


Necesitaba una solución simple, así que me helped :

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; }


Otra solución simple es agregar un espacio adicional para el pie de página de la última sección de la tabla:

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

También podemos agregar nuestro ícono a esta área. :)


Por el bien de cualquiera que se encuentre con este problema, estoy publicando los métodos necesarios aquí:

- (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; }


Prueba mi codificación, esto ayudará para ypu

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


Puede intentar agregar un UITableViewController al UIViewController en lugar de solo una vista de tabla. De esta forma, puede llamar a viewablelleverAction de UITableViewController y todo parecerá que funciona.

Ejemplo:

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


- (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; }]; }

Y en - (void) viewDidLoad

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

Entonces

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