ios uinavigationcontroller uitoolbar uikeyboard uiresponder

ios - InputAccessoryView atracado en la parte inferior



uinavigationcontroller uitoolbar (5)

Estoy tratando de lograr un comportamiento de posicionamiento similar a la barra de entrada de texto inferior en la aplicación de mensajes de Apple.

He intentado muchos enfoques, búsquedas altas y bajas y hay muchas preguntas similares, pero ninguna ha sido satisfactoria.

Para especificar:

  1. Hay una UIToolbar en la parte inferior de la vista
  2. La barra de herramientas es para seguir el teclado mientras el teclado aparece y desaparece
  3. La barra de herramientas debe permanecer en la parte superior del teclado cuando el teclado está visible
  4. Cuando el teclado está oculto, la barra de herramientas permanece ("acoplada") en la parte inferior de la vista

Las soluciones propuestas:

Anima manualmente la barra de herramientas en respuesta a las notificaciones de apariencia del teclado

Esta solución no cumple con un caso especial del segundo requisito ( la barra de herramientas es seguir el teclado cuando el teclado aparece y desaparece ):

  • En iOS 7, se introdujo UIScrollViewKeyboardDismissMode . Permite un gesto interactivo para descartar el teclado. A medida que el usuario pasa el borde superior del teclado, el marco del teclado sigue gradualmente. Esta solución no hace nada para acomodar este comportamiento y simplemente deja la barra de herramientas varada en su posición animada.

Además, esta solución tampoco cumple un caso especial del tercer requisito ( la barra de herramientas debe permanecer en la parte superior del teclado cuando el teclado está visible ):

  • Rotación. Esta solución requiere un código adicional, molesto y extraño (como veremos en la próxima solución propuesta) para rotar la barra de herramientas en respuesta a la rotación del dispositivo.

Otro problema con esta solución:

  • Altura del teclado Con esta solución, la barra de herramientas no se supone que forma parte de la altura del teclado, por lo que se debe escribir un código adicional para permitir el ajuste adecuado del contenido.

Siguiente solución propuesta:

Use la UIResponder de inputAccessoryView

Esta solución parece ser la forma en que Apple pretendía apoyar este tipo de comportamiento, ya que resuelve todas las deficiencias de la animación manual de la barra de herramientas. Pero esta solución omite por completo el cuarto requisito ( cuando el teclado está oculto, la barra de herramientas permanece ("acoplada") en la parte inferior de la vista ).

Parece que la solución es usar el UIResponder de inputAccessoryView , pero de alguna manera haciendo que inputAccessoryView no se mueva debajo de la vista. Estoy buscando un código limpio para lograr esto. Existen intentos elaborados, casi nobles, en otros lugares, pero como se mencionó, no cumplen con los requisitos.

En mi caso particular, estoy buscando utilizar la barra de herramientas de UINavigationController , que conlleva problemas adicionales, ya que este no es el comportamiento previsto para UINavigationController . No importa, estoy dispuesto a introducir algunas soluciones hacky para lograr eso.


Así que sé que esta es una publicación anterior y no estoy seguro si resolvió esto o no, pero encontré la manera de que esto funcione. Creo que hay un error en el inputAccessoryView, pero he creado una solución hacky para que se comporte como lo hace la aplicación de mensajes. Creo que proporcioné todo el código necesario para implementar el trabajo. Voy a tratar de obtener una publicación de blog más apropiada en algún momento en el futuro cercano, con una descripción más detallada de mis hallazgos. Cualquier pregunta, házmelo saber.

@property(nonatomic,assign)BOOL isFirstKeyboard; //workaround for keyboard bug @property(nonatomic,assign)BOOL isViewAppear; @property(nonatomic,strong)ChatBarView *chatView; //custom chat bar view @property(nonatomic,strong)UIView *footerPadView; //just to add some nice padding //////////////////////////////////////////////////////////////////////////////////////////////////// //in the view did load - (void)viewDidLoad { //more app specific code... self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive; self.chatView.textView.inputAccessoryView = self.chatView; } //////////////////////////////////////////////////////////////////////////////////////////////////// -(void)done { self.isFirstKeyboard = YES; [self.chatView.textView becomeFirstResponder]; } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void) moveTextViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up { if(!self.isViewAppear) return; //NSLog(@"keyboard is: %@", up ? @"UP" : @"Down"); if(!up && !self.isFirstKeyboard) [self performSelector:@selector(done) withObject:nil afterDelay:0.01]; else if(!up & self.isFirstKeyboard) { self.isFirstKeyboard = NO; [self.view addSubview:self.chatView]; CGRect frame = self.chatView.frame; frame.origin.y = self.view.frame.size.height - self.chatView.frame.size.height; self.chatView.frame = frame; } else { 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]; // Animate up or down [UIView beginAnimations:nil context:nil]; if(up) [UIView setAnimationDuration:0.2]; else [UIView setAnimationDuration:0.3]; [UIView setAnimationCurve:animationCurve]; CGRect frame = self.footerPadView.frame; CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil]; if (up) frame.size.height = keyboardFrame.size.height - self.chatView.frame.size.height; else frame.size.height = 0; self.footerPadView.frame = frame; self.tableView.tableFooterView = self.footerPadView; [UIView commitAnimations]; } } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void)keyboardWillShow:(NSNotification *)aNotification { [self moveTextViewForKeyboard:aNotification up:YES]; } //////////////////////////////////////////////////////////////////////////////////////////////////// - (void)keyboardWillHide:(NSNotification *)aNotification { [self moveTextViewForKeyboard:aNotification up:NO]; } ////////////////////////////////////////////////////////////////////////////////////////////////////


Hay una solución excelente, fácil de implementar, de código abierto para esto de parte de las buenas personas de Slack: github.com/slackhq/SlackTextViewController .

A continuación, le mostramos cómo implementar una vista con una barra de herramientas acoplada en cuatro pasos:

  1. Instala el pod en tu proyecto. ( http://cocoapods.org/?q=SlackTextViewController )
  2. Si está escribiendo una aplicación en Swift, cree un encabezado para tender un puente entre su código Swift y sus clases Obj-C. Aquí hay un buen recorrido rápido sobre eso . (El encabezado puente no será necesario una vez que las clases se traducen a Swift, ¿alguien quiere colaborar en eso?)
  3. Cree un MessageViewController que herede de SLKTextViewController , sin necesidad de escribir más código que este:

    import Foundation import UIKit class MessageViewController: SLKTextViewController { required init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) } }

  4. En Storyboard, crea un controlador de vista que hereda de MessageViewController.
  5. Pruebe la aplicación en un dispositivo o emulador, verá una hermosa barra de texto acoplada que también (como bonificación) se expande a medida que el usuario escribe líneas de texto adicionales.

Apoyos al equipo de Slack para extraer un pod tan útil.


La solution anterior de Jonathan Badeen funcionó para mí. Aquí hay un código de Arik muestra cómo implementarlo (esto debe ir en su controlador de vista apropiado):

- (BOOL)canBecomeFirstResponder{ return YES; } - (UIView *)inputAccessoryView{ return self.inputAccessoryToolbar; // where inputAccessoryToolbar is your keyboard accessory view }


Me acaba de mostrar "la" solución de Jason Foreman (@threeve). En su controlador de vista (sí, ver el controlador) agregue inputAccessoryView: y devuelva la vista que desea acoplar en la parte inferior y mueva con el teclado. Simplemente funciona. La vista no necesita estar en su jerarquía de vista, sino que será insertada por el controlador de vista automáticamente.

edit: también implemente canBecomeFirstResponder y devuelva SÍ (como notó Max Seelemann). reloadInputViews también puede ser útil.


Para aquellos que buscan la versión Swift:

Conecte su barra de herramientas (en mi caso '' myToolBar '') en su controlador de vista. A continuación, anule el método canBecomeFirstResponder y anule la variable de inputAccessoryView . Además, no se olvide de agregar self.myToolBar.removeFromSuperview() o de lo contrario xcode se quejará.

class ViewController: UIViewController { @IBOutlet var myToolBar: UIToolbar! override func canBecomeFirstResponder() -> Bool { return true } override var inputAccessoryView:UIView{ get{ return self.myToolBar } } override func viewDidLoad() { super.viewDidLoad() self.myToolBar.removeFromSuperview() } }