Ottieni UITableView per scorrere fino al campo UIText selezionato ed evitare di essere nascosto dalla tastiera

Ho un UITextField in una vista tabella su un UIViewController (non un UITableViewController ). Se la vista tabella è su un UITableViewController , la tabella scorrerà automaticamente al campo di testo in corso di modifica per impedire che venga nascosto dalla tastiera. Ma su un UIViewController no.

Ho provato per un paio di giorni a leggere diversi modi per provare a farlo e non riesco a farlo funzionare. La cosa più vicina che scorre effettivamente è:

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

Tuttavia, questo scorre solo la tabella nella riga più in alto. Quello che sembra un compito facile è stato un paio di giorni di frustrazione.

Sto usando il seguente per build le celle 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; } 

Ho il sospetto che riesca a far indexPath.row correttamente se posso in qualche modo passare indexPath.row nel metodo textFieldDidBeginEditing ?

Qualsiasi aiuto è apprezzato.

Nella mia app, ho usato con successo una combinazione di contentInset e scrollToRowAtIndexPath come questo:

Quando vuoi visualizzare la tastiera, aggiungi un contentInset in fondo al tuo tavolo con l’altezza desiderata:

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

Quindi, puoi tranquillamente usare

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

Aggiungendo contentInset, anche se ci si concentra sull’ultima cella, tableView sarà ancora in grado di scorrere. Assicurati che quando stai chiudendo la tastiera, resetti contentInset.

MODIFICARE:
Se si dispone di una sola sezione (è ansible sostituire cell_section con 0) e utilizzare il tag textView per informare la riga della cella.

Controlla questo per Scorri UITextField sopra la tastiera in UITableView O UIScrollView

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

E in - (void) viewDidLoad

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

Poi

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

Questo è un tweak per la risposta di FunkyKat (grande grazie FunkyKat!). Sarebbe probabilmente utile non codificare UIEdgeInsetsZero per la futura compatibilità iOS.

Invece, chiedo il valore di incasso corrente e ritouch il valore in basso, se necessario.

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

Per il bene di qualcun altro in questo problema, sto postando qui i metodi necessari:

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

Prova la mia codifica, questo aiuterà per ypu

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

Apple ha un post ufficiale che spiega come farlo naturalmente come fanno in UITableViewController. La mia risposta StackOverflow ha spiegato questo insieme a una versione rapida.

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

Avevo bisogno di una soluzione semplice, quindi per me ha aiutato :

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

inserisci la descrizione dell'immagine qui

È necessario ridimensionare il TableView stesso in modo che non vada sotto la tastiera.

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

In alternativa, puoi utilizzare una notifica della tastiera; questo funziona leggermente meglio perché hai più informazioni ed è più coerente in termini di conoscenza della tastiera:

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

E poi attuare:

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

Il mio codice Forse qualcuno sarà utile: Testo personalizzatoCampo campo in tableView

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

Nel mio caso il mio UITableview era all’interno di un altro UIView e UIvie era nel principale UIScrollview. Quindi ho usato una soluzione più generale per quel tipo di problemi. Ho semplicemente trovato la coordinata Y della mia cella nello specifico UIScrollView e poi ho fatto scorrere verso il punto corretto:

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

Un’altra soluzione semplice è l’aggiunta di uno spazio aggiuntivo per il piè di pagina dell’ultima sezione della tabella:

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

Possiamo aggiungere la nostra icona anche in quest’area. 🙂

Puoi provare ad aggiungere un UITableViewController a UIViewController invece di una semplice tabella. In questo modo è ansible chiamare viewWillAppear di UITableViewController e tutto sembrerà funzionare.

Esempio:

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

Ho aggiunto una piccola funzione alle risposte @FunkyKat e @bmauter (ottima risposta a proposito, dovrebbe essere quella accettata)

Gli inserti del bordo della vista tabella normale vengono conservati, prima / dopo l’apparizione della tastiera.

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