UITextView in a UITableViewCell El cambio de tamaño automático suave muestra y oculta el teclado en el iPad, pero funciona en iPhone
ios (2)
He implementado un UITableViewCell personalizado que incluye un UITextView que cambia de tamaño automáticamente según el tipo de usuario, similar al campo "Notas" en la aplicación Contactos. Funciona correctamente en mi iPhone, pero cuando lo estoy probando en el iPad, estoy teniendo un comportamiento muy extraño: cuando llegas al final de una línea, el teclado se oculta por un milisegundo y luego vuelve a aparecer de inmediato. Lo escribiría como simplemente un error peculiar, pero en realidad causa cierta pérdida de datos, ya que si usted está escribiendo, pierde un carácter o dos. Aquí está mi código:
El código
// returns the proper height/size for the UITextView based on the string it contains.
// If no string, it assumes a space so that it will always have one line.
- (CGSize)textViewSize:(UITextView*)textView {
float fudgeFactor = 16.0;
CGSize tallerSize = CGSizeMake(textView.frame.size.width-fudgeFactor, kMaxFieldHeight);
NSString *testString = @" ";
if ([textView.text length] > 0) {
testString = textView.text;
}
CGSize stringSize = [testString sizeWithFont:textView.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
return stringSize;
}
// based on the proper text view size, sets the UITextView''s frame
- (void) setTextViewSize:(UITextView*)textView {
CGSize stringSize = [self textViewSize:textView];
if (stringSize.height != textView.frame.size.height) {
[textView setFrame:CGRectMake(textView.frame.origin.x,
textView.frame.origin.y,
textView.frame.size.width,
stringSize.height+10)]; // +10 to allow for the space above the text itself
}
}
// as per: https://stackoverflow.com/questions/3749746/uitextview-in-a-uitableviewcell-smooth-auto-resize
- (void)textViewDidChange:(UITextView *)textView {
[self setTextViewSize:textView]; // set proper text view size
UIView *contentView = textView.superview;
// (1) the padding above and below the UITextView should each be 6px, so UITextView''s
// height + 12 should equal the height of the UITableViewCell
// (2) if they are not equal, then update the height of the UITableViewCell
if ((textView.frame.size.height + 12.0f) != contentView.frame.size.height) {
[myTableView beginUpdates];
[myTableView endUpdates];
[contentView setFrame:CGRectMake(0,
0,
contentView.frame.size.width,
(textView.frame.size.height+12.0f))];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int height;
UITextView *textView = myTextView;
[self setTextViewSize:textView];
height = textView.frame.size.height + 12;
if (height < 44) { // minimum height of 44
height = 44;
[textView setFrame:CGRectMake(textView.frame.origin.x,
textView.frame.origin.y,
textView.frame.size.width,
44-12)];
}
return (CGFloat)height;
}
Los problemas
Entonces, aquí está lo que está pasando.
- Este código funciona correctamente al 100% en mi iPhone y en el simulador de iPhone. A medida que escribo el texto, el UITextView crece sin problemas y el UITableViewCell junto con él.
- En el simulador de iPad, sin embargo, se pone loco. Funciona bien mientras escribe en la primera línea, pero cuando llega al final de una línea, el teclado desaparece y luego vuelve a aparecer inmediatamente, de modo que si el usuario continúa escribiendo la aplicación pierde uno o dos caracteres.
- Aquí hay algunas notas adicionales sobre los comportamientos extraños que he notado que pueden ayudar a explicarlo:
- Además, he encontrado que al eliminar las líneas
[myTableView beginUpdates]; [myTableView endUpdates];
[myTableView beginUpdates]; [myTableView endUpdates];
en la funcióntextViewDidChange:(UITextView *)textView
hace que UITextView crezca correctamente y no muestre ni oculte el teclado, pero desafortunadamente, el UITableViewCell no crece a la altura adecuada. - ACTUALIZACIÓN: Siguiendo estas instrucciones , ahora puedo detener el extraño movimiento del texto; pero el teclado todavía se esconde y muestra, lo que es muy extraño.
- Además, he encontrado que al eliminar las líneas
¿Alguien tiene alguna idea de cómo hacer que el teclado se muestre continuamente, en lugar de ocultarlo y mostrarlo cuando llegas al final de la línea en el iPad?
PD: No estoy interesado en usar ThreeTwenty.
Tuve el mismo problema con una aplicación de iPad y se me ocurrió otra solución sin tener que calcular la altura del texto en sí.
Primero cree un UITableViewCell personalizado en IB con un UITextField colocado en el contentView de la celda. Es importante configurar la vista de texto scrollEnabled en NO y la AutoresizingMask en flexibleWidth y flexibleHeight.
En ViewController, implemente el método delegado de la vista de texto -textViewDidChanged: como se muestra a continuación, donde textHeight es una variable de instancia con el tipo CGFloat y -tableViewNeedsToUpdateHeight es un método personalizado que definiremos en el siguiente paso.
- (void)textViewDidChange:(UITextView *)textView
{
CGFloat newTextHeight = [textView contentSize].height;
if (newTextHeight != textHeight)
{
textHeight = newTextHeight;
[self tableViewNeedsToUpdateHeight];
}
}
El método -tableViewNeedsToUpdateHeight llama a beginUpdates y endUpdates de la vista de tabla, por lo que la propia vista de tabla llamará a -tableView: heightForRowAtIndexPath: método de delegado.
- (void)tableViewNeedsToUpdateHeight
{
BOOL animationsEnabled = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[table beginUpdates];
[table endUpdates];
[UIView setAnimationsEnabled:animationsEnabled];
}
En la vista de tabla -tableView: heightForRowAtIndexPath: método delegado, necesitamos calcular la nueva altura para la celda de la vista de texto basada en textHeight .
Primero debemos cambiar el tamaño de la altura de las celdas de la vista de texto a la altura máxima disponible (después de restar la altura de todas las demás celdas de la vista de tabla). Luego verificamos si el textHeight es más grande que la altura calculada.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat heightForRow = 44.0;
if ([indexPath row] == kRowWithTextViewEmbedded)
{
CGFloat tableViewHeight = [tableView bounds].size.height;
heightForRow = tableViewHeight - ((kYourTableViewsNumberOfRows - 1) * heightForRow);
if (heightForRow < textHeight)
{
heightForRow = textHeight;
}
}
return heightForRow;
}
Para una mejor experiencia de usuario, configure las inserciones de contenido de la vista de tabla para la parte inferior a, por ejemplo, 50.0.
Lo he probado en el iPad con iOS 4.2.1 y funciona como se esperaba.
Florian
debe devolver NO en:
-(BOOL) textViewShouldEndEditing:(UITextView *)textView
Si desea mostrar el teclado en todo momento. Debe manejar los casos, cuyo teclado debe estar oculto, devolviendo SÍ a esta función de delegado.
editar:
Cavé un poco más, cuando llamó [tableView endUpdates] , básicamente hace 3 cosas:
- Desactiva la interacción del usuario en el tableView
- Actualiza los cambios de celda.
- Permite la interacción del usuario en el tableView
La diferencia entre los SDK (plataformas) está en el método [UIView setUserInteractionEnabled] . Como UITableView no sobrescribe el método setUserInteractionEnabled , se llama desde super (UIView).
iPhone cuando se llama a setUserInteractionEnabled , busca un campo privado _shouldResignFirstResponderWithInteractionDisabled que devuelve NO como predeterminado, por lo que no renuncia al primer respondedor (UITextView)
Pero en el iPad no hay tal comprobación AFAIK, por lo que renuncia a UITextView en el paso 1 , se enfoca y hace que responda primero en el paso 3
Básicamente, textViewShouldEndEditing, que le permite mantener el enfoque, de acuerdo con los documentos del SDK, es su única opción en ATM.
Este método se llama cuando se solicita a la vista de texto que renuncie al primer estado de respuesta. Esto puede ocurrir cuando el usuario intenta cambiar el enfoque de edición a otro control. Sin embargo, antes de que el enfoque cambie realmente, la vista de texto llama a este método para darle a su delegado la oportunidad de decidir si debería hacerlo.