ios - UITableView reloadData llama automáticamente a resignFirstResponder
(12)
Como lo menciona @Eiko, ¡esto funciona para mí!
Actualice la celda en el método pickerView:didSelectRow:inComponent:
:
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
TableViewCell *cell = (TableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:pickerView.tag inSection:0]];
/*
Update your cell here.
*/
// Reload TableViewCell will resign the PickerView, so we need to focus it back.
[self.tableView reloadData];
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
NSArray* indexArray = [NSArray arrayWithObjects:indexPath, nil];
[self.tableView reloadRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationNone];
[cell.textField becomeFirstResponder];
}
Tengo este UITableView con celdas personalizadas que solo pueden obtener valores predefinidos, por lo tanto, uso un UIPickerView como su inputView. Todo está muy bien hasta que edite un campo y necesite mostrar su valor actualizado.
Para hacer las cosas más claras y fáciles de mantener, hice delegados y fuentes de datos como clases separadas, y uso las notificaciones para hacerlas interactuar con el tableView. Entonces, después de elegir un valor de UIPickerView, la fuente de datos de tableView recibe una notificación y, a su vez, notifica al ViewController principal que contiene una referencia a tableView. Desde allí llamo
[_tableView reloadData];
y todo parece funcionar, excepto que el UIPickerView desaparece, creo porque las celdas se regeneran y en algún lugar se llama a algún resignFirstResponder, o algo así. ¿Hay alguna otra forma de hacer que el tableView actualice sus valores sin tener que implementar un método personalizado en algún lugar que lo haga, que sería bastante feo?
Encontré el mismo problema, ninguna de las respuestas anteriores funcionó a la perfección (veo que el teclado rebota hacia arriba, hacia abajo, etc.).
Después de esta publicación de SO , solucioné el problema llamando
[tableView beginUpdates];
[tableView endUpdates];
Esto funcionó para mí, las filas de la tabla obtienen actualizaciones e incluso expanden / contraen (si está cambiando la altura de las filas de forma dinámica) con una buena animación, todo sin renunciar a la primera respuesta o incluso al iniciar el descarte del teclado.
Esto no desplazará su vista de tabla para adaptarse a cualquier fila expandida, por lo que pongo el fragmento de arriba en el método dedicado, fe:
- (void)tableView:(UITableView *)tableView reloadRowWhileShowingKeyboard:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
Esto se parece al comportamiento esperado: el selector pertenece a una celda en particular, esa celda se vuelve a cargar y ya no es la primera respuesta. Supongo que uno tenía que seleccionar un elemento específico de todos modos para que aparezca el seleccionador, es decir, para que sea el primero en responder.
Por lo tanto, debe hacer que se convierta en el primero en responder nuevamente después de volver a cargar, o actualice la celda específica directamente.
Lo resolví subclasificando UITextView, anulando - (BOOL) resignFirstResponder y agregando un BOOL canResign. esta variable se establece antes de volver a cargar los datos y se desarma un poco después.
Puede resolver este problema transfiriendo temporalmente el estado del primer respondedor a otro objeto. Por lo general, transfiere el control de la vista de entrada a su ViewController. Dado que su UIViewController también hereda de UIResponder, puede hacer algo como esto:
en didSelect {....
[su ViewController becomeFirstRespoder];
[_tableView reloadData];
[yourInputField becomeFirstResponder];
....}
Por lo tanto, una vez que la tabla se vuelve a cargar, puede transferir el estado de firstResponder a su etiqueta / campo. De forma predeterminada, canBecomeFirstResponder está establecido en NO. Por lo tanto, es posible que deba anular el mismo en su ViewController. Además, es posible que necesite hacer que inputView para su controlador de vista sea el mismo que su UIPicker, de lo contrario, podría descartar su selector y mostrar un teclado.
Puedes seguir este enfoque, no el mejor, pero funciona:
// pass the responder to a temporary (hidden) textField
[_tmpTextField becomeFirstResponder];
// reload data
[_tableView reloadData];
// reloadData is definitely async...
// so pass the responder back in a timed op
double delayInSeconds = 0.1;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[_textField becomeFirstResponder];
});
Puse mi UISearchBar en su propia sección en una UITableView. Al activar la búsqueda, me aseguré de actualizar solo las secciones que no contienen la barra de búsqueda.
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation
Rastree qué teclado de la celda está activo y luego obtenga esa celda en particular por cellForRowAtIndexPath
y haga textView firstResponder
self.tableView.reloadData()
if let indexPath = self.activeIndexPath{
if let cell = createFormTableView.cellForRow(at: indexPath) as? TextViewTableViewCell {
cell.txtViewInput.becomeFirstResponder()
}
}
Si enfrentas este problema con una barra de búsqueda, lo hice por mí en iOS 6:
- Crea una instancia de UISearchBar y agrégala como una subvista a tu UITableView en la parte superior.
- Cree una primera celda ficticia en su UITableView para que la barra de búsqueda solo bloquee esta celda ficticia y no su celda real con datos.
Solución Swift:
podemos anular canResignFirstResponder predeterminado subclasificando UITextfiled
class CustomField: UITextField{
var canResign:Bool = false
override var canResignFirstResponder: Bool{
return canResign
}
}
todo lo que necesita para establecer la variable canResign antes y después de la instrucción de recarga.
cell.offerInputTextField.canResign = false
tableView.reloadData()
cell.offerInputTextField.canResign = true
no olvide asignar el campo de texto de la clase personalizada como CustomField.
agregando:
[yourSearchBar becomeFirstResponder];
despues de ti:
[_tableView reloadData];
Hizo el truco
customTextField.canResign = NO;
[self.tableView reloadData];
customTextField.canResign = YES;
El campo de texto personalizado se deriva de UITextField.
.h
@interface CustomTextField : UITextField
@property (nonatomic,assign) BOOL canResign;
@end
.metro
- (BOOL)canResignFirstResponder
{
return self.canResign;
}
Asegúrese de que su campo de texto personalizado no se vuelva a crear en la recarga de la vista de tabla.