when appears iphone keyboard uitextview

iphone - move view when keyboard appears swift 4



¿Cómo cambiar el tamaño de UITextView en iOS cuando aparece un teclado? (10)

Hay UITextView insertado en la pestaña en UITabBarController (en el iPhone).

  1. Rellene UITextView con muchas líneas.
  2. Mostrar un teclado para editar texto.

¿Que pasa? El teclado oculta una mitad de UITextView con cursor. No se puede editar el texto como resultado.

¿Cómo resolver el problema para todos los dispositivos móviles de Apple (con una resolución de pantalla diferente)? ¡Muchas gracias por la ayuda!


Años atrás, la pregunta sigue siendo actual. Apple definitivamente debería manejar todas estas cosas por sí mismo. Pero no lo hace. Aquí está la nueva solución basada en la documentation oficial de Apple más correcciones de errores. Es compatible con iOS 8, iOS 9, inputAccessoryView y está listo para nuevas versiones de iOS y nuevos dispositivos.

/* Apple''s solution to resize keyboard but with accessory view support */ - (void)keyboardDidShow:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardHeight, 0.0); editor.contentInset = contentInsets; editor.scrollIndicatorInsets = contentInsets; } - (void)keyboardWillHide:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; editor.contentInset = contentInsets; editor.scrollIndicatorInsets = contentInsets; // button to hide the keyboard buttonDone.enabled = false; } /* Fix issues with size classes and accessory view */ - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; // fix incorrect size of the inputAccessoryView when size class changed // willTransitionToTraitCollection and traitCollectionDidChange can''t help us if (editor && editor.inputAccessoryView && !editor.inputAccessoryView.hidden) { [editor resignFirstResponder]; } } /* Hide accessory view if a hardware keyboard is present */ #define gThresholdForHardwareKeyboardToolbar 160.f // it''s minimum height of the software keyboard on iPhone 4 in landscape mode - (bool)isExternalKeyboard:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGRect keyboardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; double keyboardHeight = [[UIScreen mainScreen] bounds].size.height - keyboardFrame.origin.y; return keyboardHeight < gThresholdForHardwareKeyboardToolbar; } - (void)keyboardWillShow:(NSNotification*)aNotification { if ([self isExternalKeyboard:aNotification]) { // hardware keyboard is present if (editor && editor.inputAccessoryView) { editor.inputAccessoryView.hidden = true; } } else { // only on-screen keyboard if (editor && editor.inputAccessoryView) { editor.inputAccessoryView.hidden = false; } } // button to hide the keyboard buttonDone.enabled = true; }



Con Auto Layout, es mucho más fácil (siempre que entiendas Auto Layout) manejar:

En lugar de intentar identificar y cambiar el tamaño de las vistas afectadas, simplemente cree un marco principal para todos los contenidos de su vista. Entonces, si aparece el kbd, cambia el tamaño del marco, y si ha configurado las restricciones correctamente, la vista reorganizará todas sus vistas secundarias muy bien. No es necesario jugar con un montón de código difícil de leer para esto.

De hecho, en una pregunta similar encontré un enlace a este excelente tutorial sobre esta técnica.


El mejor resultado fue alcanzado por el siguiente código. Tampoco olvide establecer el color de fondo en UIView y colocar UITextView antes que otros controles de la pantalla superior (por ejemplo, UITabBar).

La edición de un texto al final todavía no es perfecta ahora. Puedes intentar mejorar.

FirstViewController.h:

@interface FirstViewController : UIViewController { IBOutlet UIBarButtonItem *buttonDone; IBOutlet UITextView *textView; UITabBarController* tabBarController; // set from superview in AppDelegate (MainWindow.xib) } @property (nonatomic, retain) UITabBarController* tabBarController;

FirstViewController.m:

@synthesize tabBarController; - (void)viewDidAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up { NSDictionary* userInfo = [aNotification userInfo]; NSTimeInterval animationDuration; UIViewAnimationCurve animationCurve; CGRect keyboardEndFrame; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:animationDuration]; [UIView setAnimationCurve:animationCurve]; CGRect newFrame = textView.frame; CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil]; keyboardFrame.size.height -= tabBarController.tabBar.frame.size.height; newFrame.size.height -= keyboardFrame.size.height * (up?1:-1); textView.frame = newFrame; [UIView commitAnimations]; } - (void)keyboardWillShown:(NSNotification*)aNotification { buttonDone.enabled = true; [self moveTextViewForKeyboard:aNotification up:YES]; } - (void)keyboardWillHide:(NSNotification*)aNotification { buttonDone.enabled = false; [self moveTextViewForKeyboard:aNotification up:NO]; }

PS Es difícil codificar para iOS sin ...


En resumen, registre la notificación del teclado y haga un cambio de tamaño cuando se le notifique.


Intenté la mejor respuesta aquí, sin embargo, encontré un problema en ella. Si tiene otro campo de texto en la misma página, haga clic en el campo de texto y mostrará el teclado. Notarás que la vista de texto se reduce. Sin embargo, si hace clic en la vista de texto ahora, notará que el tamaño de la vista de texto se reduce de nuevo, mientras que no debería hacerlo.

Mi solución a este problema es mantener una propiedad en el controlador de vista que representa el estado del teclado (se muestra / oculta). Si el teclado está visible actualmente, la vista de texto no debe reducirse. En caso de que esté utilizando teclados de diferentes tamaños para diferentes entradas de texto, también debe mantener el tamaño del teclado anterior.

Tenga en cuenta que esta solución tampoco tuvo en cuenta la orientación diferente, lo que puede afectar la forma en que calcula el tamaño de la vista de texto.

@implementation MyViewController { BOOL keyboardShown; NSInteger keyboardHeight; } - (void)moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{ NSDictionary* userInfo = [aNotification userInfo]; NSTimeInterval animationDuration; UIViewAnimationCurve animationCurve; CGRect keyboardEndFrame; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:animationDuration]; [UIView setAnimationCurve:animationCurve]; CGRect newFrame = self.textView.frame; CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil]; NSInteger oldHeight = self->keyboardShown ? self->keyboardHeight : 0; NSInteger newHeight = up ? keyboardFrame.size.height : 0; NSInteger change = oldHeight - newHeight; self->keyboardShown = up; self->keyboardHeight = keyboardFrame.size.height; newFrame.size.height += change; self.textView.frame = newFrame; [UIView commitAnimations]; }


Me encontré con varios problemas al intentar que mi vista de texto se desplace y anime correctamente tanto para iOS 7 como para iOS 8, y con la nueva función QuickType. Al principio me centré en animar las inserciones de vista de desplazamiento, pero el comportamiento difería entre iOS 7 y 8 y no podía hacer que funcionara correctamente para ambas.

Luego me di cuenta de que puedo simplificar las cosas simplemente enfocándome en el marco y esto me funcionó con un código mucho más simple. En resumen:

  • regístrese para el UIKeyboardDidChangeFrameNotification (esto notificará cuando se muestre / oculte también el QuickType).
  • descubra cuánto espacio vertical necesita cambiar el marco de la vista de texto.
  • animar el cambio de tamaño de marco.

Aquí hay un código que ilustra lo anterior:

- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidChangeFrameWithNotification:) name:UIKeyboardDidChangeFrameNotification object:nil]; } - (void)keyboardDidChangeFrameWithNotification:(NSNotification *)notification { CGFloat keyboardVerticalIncrease = [self keyboardVerticalIncreaseForNotification:notification]; [self animateTextViewFrameForVerticalOffset:keyboardVerticalIncrease]; } - (CGFloat)keyboardVerticalIncreaseForNotification:(NSNotification *)notification { CGFloat keyboardBeginY = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].origin.y; CGFloat keyboardEndY = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].origin.y; CGFloat keyboardVerticalIncrease = keyboardBeginY - keyboardEndY; return keyboardVerticalIncrease; } - (void)animateTextViewFrameForVerticalOffset:(CGFloat)offset { CGFloat constant = self.bottomConstraint.constant; CGFloat newConstant = constant + offset; self.bottomConstraint.constant = newConstant; [self.view layoutIfNeeded]; [UIView animateWithDuration:0.5 animations:^{ [self.view layoutIfNeeded]; }]; }

Una nota rápida sobre la animación. Utilicé Autolayout, así que decidí animar NSAutoLayoutConstraint de la vista de texto, no el marco directamente. Y para hacer esto, llamo [self.view layoutIfNeeded] antes y dentro del bloque de animación. Esta es la forma correcta de animar restricciones. He encontrado este consejo here .


Primero agregue algunos métodos de teclado al NSNotificationCenter defaultCenter

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

A continuación, puede cambiar los tamaños:

- (void)keyboardWillShow:(NSNotification *)notif { [thetextView setFrame:CGRectMake(20, 49, 280, 187)]; //Or where ever you want the view to go } - (void)keyboardWillHide:(NSNotification *)notif { [thetextView setFrame:CGRectMake(20, 49, 280, 324)]; //return it to its original position }


Vale la pena señalar que la respuesta con votos más altos solo funciona si el dispositivo está en modo retrato (y no al revés); en otros modos, los límites salen mal. Creo que podrías arreglar esto usando límites para arreglarlo, pero no pude hacer que funcionara, por lo que el siguiente ajuste funcionó para mí:

- (void)moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up { NSDictionary* userInfo = [aNotification userInfo]; NSTimeInterval animationDuration; UIViewAnimationCurve animationCurve; CGRect keyboardEndFrame; [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:animationDuration]; [UIView setAnimationCurve:animationCurve]; CGRect newFrame = self.view.frame; if (keyboardEndFrame.size.height >keyboardEndFrame.size.width) { //we must be in landscape if (keyboardEndFrame.origin.x==0) { //upside down so need to flip origin newFrame.origin = CGPointMake(keyboardEndFrame.size.width, 0); } newFrame.size.width -= keyboardEndFrame.size.width * (up?1:-1); } else { //in portrait if (keyboardEndFrame.origin.y==0) { //upside down so need to flip origin newFrame.origin = CGPointMake(0, keyboardEndFrame.size.height); } newFrame.size.height -= keyboardEndFrame.size.height * (up?1:-1); } self.view.frame = newFrame; [UIView commitAnimations]; }


- (void)registerKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; } - (void)unregisterKeyboardNotifications { [[NSNotificationCenter defaultCenter] removeObserver:self]; } -(void) keyboardWillHide:(NSNotification *)note { //adjust frame } -(void) keyboardWillShow:(NSNotification *)note { //adjust frame }

y anular el registro de la notificación también en el dealloc

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