Cubiertas de teclado para iPhone UITextField

Tengo una aplicación donde, en Interface Builder , configuré una UIView que tiene un campo de texto cerca de la parte inferior de la vista. Cuando ejecuto la aplicación y trato de ingresar texto en ese campo, el teclado se desliza hacia arriba del campo para que no pueda ver lo que estoy escribiendo hasta que vuelva a ocultar el teclado.

¿Alguien más se ha encontrado con este problema y ha encontrado una buena manera de resolverlo sin hacer que la vista padre sea desplazable o mover el campo de texto más arriba en la pantalla?

La solución habitual es deslizar el campo (y todo lo que está sobre él) hacia arriba con una animación, y luego volver a bajar cuando haya terminado. Es posible que deba colocar el campo de texto y algunos de los otros elementos en otra vista y deslice la vista como una unidad. (Yo llamo a estas cosas “platos” como en “placas tectónicas”, pero así soy yo). Pero aquí está la idea general si no necesitas ser elegante.

 - (void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField: textField up: YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField: textField up: NO]; } - (void) animateTextField: (UITextField*) textField up: (BOOL) up { const int movementDistance = 80; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? -movementDistance : movementDistance); [UIView beginAnimations: @"anim" context: nil]; [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimations]; } 

Esto funcionó de maravillas para mí deslizando uitextfields

En particular, tiene el beneficio de calcular la distancia de animación de diapositivas dependiendo de la posición del campo de texto.

IQKeyboardManager hace esto por usted SIN NINGUNA LÍNEA DE CÓDIGO , solo necesita arrastrar y soltar el archivo fuente relacionado para proyectar. IQKeyboardManager también admite Device Orientation , Automatic UIToolbar Management , keyboardDistanceFromTextField y mucho más de lo que piensas.

enter image description here

Aquí está el diagtwig de flujo de control: Diagrama de flujo de control

Paso 1: – Se agregaron notificaciones globales de UITextField , UITextView y UIKeyboard en una clase singleton. Lo llamé IQKeyboardManager .

Paso 2: si se encuentran las UIKeyboardWillShowNotification , UITextFieldTextDidBeginEditingNotification o UITextViewTextDidBeginEditingNotification , intente obtener la instancia de topMostViewController desde la jerarquía UIWindow.rootViewController . Para descubrir adecuadamente UITextField / UITextView , se debe topMostViewController.view el marco de topMostViewController.view .

Paso 3: – Distancia de movimiento esperada calculada de topMostViewController.view con respecto al primer UITextField / UITextView respondido.

Paso 4: movió arriba / abajo topMostViewController.view.frame arriba / abajo según la distancia de movimiento esperada.

Paso 5: – Si se encuentra la UIKeyboardWillHideNotification , UITextFieldTextDidEndEditingNotification o UITextViewTextDidEndEditingNotification , intente nuevamente obtener la instancia de topMostViewController desde la jerarquía UIWindow.rootViewController .

Paso 6: – Distancia perturbada calculada de topMostViewController.view que debe restaurarse en su posición original.

Paso 7: restaurado topMostViewController.view.frame hacia abajo según la distancia perturbada.

Paso 8: instancia de instancia Singleton IQKeyboardManager instanciada en la carga de la aplicación, por lo que cada UITextField / UITextView en la aplicación se ajustará automáticamente según la distancia de movimiento esperada.

Eso es todo

Para ampliar la respuesta de Amagrammer, aquí hay una clase de muestra:

LoginViewController.h

 @interface LoginViewController : UIViewController  { } @property (nonatomic, retain) IBOutlet UITextField *emailTextField; @property (nonatomic, retain) IBOutlet UITextField *passwordTextField; 

Tenga en cuenta que estamos implementando el “UITextFieldDelegate”

LoginViewController.m

 @implementation LoginViewController @synthesize emailTextField=_emailTextField; @synthesize passwordTextField=_passwordTextField; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { //Register to receive an update when the app goes into the backround //It will call our "appEnteredBackground method [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; } return self; } - (void) animateTextField: (UITextField*) textField up: (BOOL) up { const int movementDistance = 80; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? -movementDistance : movementDistance); [UIView beginAnimations: @"anim" context: nil]; [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimations]; } - (void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField: textField up: YES]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField: textField up: NO]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; } //This is called when the app goes into the background. //We must reset the responder because animations will not be saved - (void)appEnteredBackground{ [self.emailTextField resignFirstResponder]; [self.passwordTextField resignFirstResponder]; } 

¿Qué hay de la solución oficial: Mover el contenido que se encuentra debajo del teclado

El ajuste de su contenido generalmente implica cambiar el tamaño temporalmente de una o más vistas y colocarlas de manera que el objeto de texto permanezca visible. La forma más sencilla de administrar objetos de texto con el teclado es insertarlos dentro de un objeto UIScrollView (o una de sus subclases como UITableView). Cuando se muestra el teclado, todo lo que tiene que hacer es reiniciar el área de contenido de la vista de desplazamiento y desplazar el objeto de texto deseado a su posición. Por lo tanto, en respuesta a un UIKeyboardDidShowNotification, su método de manejo haría lo siguiente:

  1. Obtenga el tamaño del teclado.
  2. Ajuste la inserción de contenido inferior de su vista de desplazamiento por la altura del teclado.
  3. Desplace el campo de texto de destino a la vista.
 // Call this method somewhere in your view controller setup code. - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil]; } // Called when the UIKeyboardDidShowNotification is sent. - (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0); scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; // If active text field is hidden by keyboard, scroll it so it's visible // Your app might not need or want this behavior. CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) { [self.scrollView scrollRectToVisible:activeField.frame animated:YES]; } } // Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; } 

Me he enfrentado al mismo problema en las celdas UITableView textField. Resuelvo este problema implementando el siguiente método para escuchar la notificación del teclado.

Observador de las notificaciones aquí:

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

Maneje esas notificaciones usando la siguiente función:

 (void)keyboardWasShown:(NSNotification*)aNotification (void)keyboardWillBeHidden:(NSNotification*)aNotification 

Mira esto. Sin molestias para ti

Esta solución es muy clara. Todo lo que tiene que hacer es agregar sus campos de texto en UIScrollView y cambiar su clase a TPKeyboardAvoidingScollView , si está usando storyboards. La vista de desplazamiento se extiende de tal forma que detectará cuándo el teclado está visible y se moverá sobre el teclado a una distancia razonable. Es la solución perfecta porque es independiente de su UIViewController . Todo lo necesario se hace dentro de la clase mencionada anteriormente. Gracias Michael Tyson y todo.

TPKeyboardAvoiding

A continuación se muestra una versión rápida de la respuesta de Amagrammer. Además, una variación con el evento UIKeyboardWillShowNotification ya que necesitaba saber el tamaño de los teclados antes de mover la vista fuera del camino.

 var keyboardHeight:CGFloat = 0 override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillChange:", name: UIKeyboardWillShowNotification, object: nil) } func textFieldDidBeginEditing(textField: UITextField) { //keyboardWillChange (below) is used instead of textFieldDidBeginEditing because textFieldDidBeginEditing //is called before the UIKeyboardWillShowNotification necessary to determine the keyboard height. } func textFieldDidEndEditing(textField: UITextField) { animateTextField(false) } func animateTextField(textFieldUp:Bool) { let movementDistance:CGFloat = keyboardHeight let movementDuration = 0.3 let movement:CGFloat = (textFieldUp ? -movementDistance : movementDistance) UIView.beginAnimations("anim", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = CGRectOffset(self.view.frame, 0, movement) UIView.commitAnimations() } func keyboardWillChange(notification:NSNotification) { let keyboardRect:CGRect = ((notification.userInfo![UIKeyboardFrameEndUserInfoKey])?.CGRectValue)! keyboardHeight = keyboardRect.height animateTextField(true) } 

Hubo un gran tutorial en la edición de campos de texto sin oscurecer (link dead now, aquí hay un enlace de Wayback: https://web.archive.org/web/20091123074029/http://acts-as-geek.blogspot.com/2009/ 11 / editing-textfields-without-obscuring.html ). Muestra cómo mover una UIView existente en UIScrollView , y desplazarse automáticamente cuando aparece el teclado.

Lo he actualizado un poco para calcular la altura correcta para el UIScrollView cuando hay controles (como una UITabBar ) debajo de UIScrollBar . Ver la publicación de la actualización de uiview .

Aquí hay una solución que usa Xcode5, iOS7:

Utilice el UITextfieldDelegate y los bloques de animación.

Esto es casi todo el código para ViewController, pero quería incluir el código de delegado para aquellos que todavía no están familiarizados con el patrón de delegado (como yo). También incluí código para ocultar el teclado cuando tocas lejos de la vista de texto.

Puede mover las vistas (botones, campos de texto, etc.) tan alto como desee, solo asegúrese de volver a colocarlas en su lugar (+100 y luego -100).

 @interface ViewController ()  @property (strong, nonatomic) IBOutlet UITextField *MyTextField; @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.MyTextField.delegate = self; } - (void)textFieldDidBeginEditing:(UITextField *)textField { NSLog(@"text began editing"); CGPoint MyPoint = self.MyTextField.center; [UIView animateWithDuration:0.3 animations:^{ self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y - 100); }]; } - (void)textFieldDidEndEditing:(UITextField *)textField { NSLog(@"text ENDED editing"); CGPoint MyPoint = self.MyTextField.center; [UIView animateWithDuration:0.3 animations:^{ self.MyTextField.center = CGPointMake(MyPoint.x, MyPoint.y + 100); }]; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.view endEditing:YES]; } 

Supongo que una forma sería mover la posición de todas las vistas desde (x, y) a (x, y-keybaardHeight) cuando se haga clic en el campo de texto y volverlo a colocar cuando se descarte el teclado, puede parecer un poco extraño ya que la vista solo aparece (tal vez no sería malo si lo anima).

 - (void)textFieldDidBeginEditing:(UITextField *)textField { CGRect frame=self.view.frame; frame.origin=CGPointMake(x...//set point here self.view.frame=frame; } 

Además de la solución de Amagrammer, si está utilizando cocos2d en modo retrato, cambie esta línea:

 self.view.frame = CGRectOffset(self.view.frame, 0, movement); 

a esto:

 [CCDirector sharedDirector].openGLView.frame = CGRectOffset([CCDirector sharedDirector].openGLView.frame, movement, 0); 

Si está utilizando cocos2d en modo horizontal, haga que lo anterior cambie y cambie los valores textFieldDidBeginEditing: en textFieldDidBeginEditing: y textFieldDidEndEditing:

 - (void)textFieldDidBeginEditing:(UITextField *)textField { [self animateTextField:textField up:NO]; } - (void)textFieldDidEndEditing:(UITextField *)textField { [self animateTextField:textField up:YES]; } 

Tuve el mismo problema y descubrí que GTKeyboardHelper era una salida fácil.

Después de arrastrar y soltar el marco en su proyecto, incluya el archivo de encabezado. Descargue y abra el proyecto de ejemplo, luego arrastre el objeto “Ayudante de teclado” desde la sección de objetos en el xib a la sección de objetos en el constructor de interfaz de su proyecto.

Arrastra y suelta todas tus vistas para que sean elementos secundarios de “Keyboard Helper”.

¿Cómo manejas la situación donde el teclado está arriba y el marco ha cambiado de tamaño con la animación y se desplazó para que el campo de texto no esté cubierto, a partir de ahí cuando selecciono otro campo de texto (aún editando el primer campo de texto) cómo no reproduzco la animación otra vez solo desplazarse un poco más si es necesario? El problema es reproducir toda la animación cuando no es necesario. Gracias

Arrastrar y soltar el marco que utilizo en mis proyectos. Admite la eliminación automática cuando toca fuera de un primer respondedor o cuando se desplaza.

GTKeyboardHelper

Por favor mira mi comentario en esto:

iPhone – El teclado oculta TextField

Simplemente deslice la vista hacia arriba y hacia abajo según sea necesario:

 - (void)textFieldDidEndEditing:(UITextField *)textField { self.currentTextField = nil; [self animateTextField: textField up: NO]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { [self.currentTextField resignFirstResponder]; return YES; } - (void) animateTextField:(UITextField*) textField up:(BOOL)up { const int movementDistance = 80; // tweak as needed const float movementDuration = 0.3f; // tweak as needed int movement = (up ? -movementDistance : movementDistance); [UIView animateWithDuration:movementDuration animations:^{ self.view.frame = CGRectOffset(self.view.frame, 0, movement); }]; } 

No se olvide de establecerse como UITextFieldDelegate y como el delegate real de TextField.

(Gracias a Ammagrammer, esta es solo una respuesta más corta usando bloques para animaciones)

Tengo algo más si quieres. El punto aquí es que desea configurar el centro de su UIView en el campo de texto que está editando.

Antes de eso, debe guardar su INITIAL_CENTER , como CGPoint , desde self.view.center y su INITIAL_VIEW como CGRect desde self.view.frame en una propiedad const.

Puedes crear un método como este:

 - (void) centerOn: (CGRect) fieldFrame { // Set up the center by taking the original view center CGPoint center = CGPointMake(INITIAL_CENTER.x, INITIAL_CENTER.y - ((fieldFrame.origin.y + fieldFrame.size.height/2) - INITIAL_CENTER.y)); [UIView beginAnimations:@"centerViewOnField" context:nil]; [UIView setAnimationDuration:0.50]; if (CGRectEqualToRect(fieldFrame,INITIAL_VIEW)) { self.view.frame = INITIAL_VIEW; [self.view setCenter:INITIAL_CENTER]; } else { [self.view setCenter:center]; } [UIView commitAnimations]; } 

Luego, en su UITextFieldDelegate , debe llamar a centerOn: (CGRect) en los siguientes métodos:

textFieldDidBeginEditing: (UITextField *) con, como parámetro, el marco del campo de texto sobre el que desea centrar.

Y tiene que llamarlo en su controlador de eventos, donde cierra el teclado,

textFieldDidEndEditing: (UITextField *) puede ser una de las formas de hacerlo, poniendo INITIAL_VIEW como un parámetro de centerOn: (CGRect) .

Creo en las versiones más nuevas de iOS (6.1+, posiblemente incluso antes), la vista subyacente, al menos para UITableView, se contrae automáticamente cuando aparece el teclado. Entonces solo necesita hacer que el campo de texto sea visible en esa vista. En init :

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil]; 

entonces:

 - (void)keyboardWasShown:(NSNotification*)notification { // Scroll the text field into view so it's not under the keyboard. CGRect rect = [self.tableView convertRect:inputView.bounds fromView:inputView]; [self.tableView scrollRectToVisible:rect animated:YES]; } 

https://github.com/ZulwiyozaPutra/Shift-Keyboard-Example Espero que esta solución haya sido de ayuda. Todos son Swift 3 escritos.

 // // ViewController.swift // Shift Keyboard Example // // Created by Zulwiyoza Putra on 11/23/16. // Copyright © 2016 Zulwiyoza Putra. All rights reserved. // import UIKit class ViewController: UIViewController, UITextFieldDelegate { //connecting textfield from storyboard @IBOutlet weak var textField: UITextField! override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) subscribeToKeyboardNotifications() } override func viewDidAppear(_ animated: Bool) { self.textField.delegate = self } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) unsubscribeFromKeyboardNotifications() } //Hide keyboard after finished editing func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } //Setup view before keyboard appeared func keyboardWillAppear(_ notification:Notification) { view.frame.origin.y = 0 - getKeyboardHeight(notification) } //Setup view before keyboard disappeared func keyboardWillDisappear(_ notification: Notification) { view.frame.origin.y = 0 } //Getting keyboard height func getKeyboardHeight(_ notification:Notification) -> CGFloat { let userInfo = notification.userInfo let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue // of CGRect return keyboardSize.cgRectValue.height } //Subscribing to notifications to execute functions func subscribeToKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(_:)), name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear(_:)), name: .UIKeyboardWillHide, object: nil) } //Unsubscribing from notifications func unsubscribeFromKeyboardNotifications() { NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil) } }