Pregunta

Estoy trabajando en una aplicación para iPad usando 3.2 SDK. Estoy tratando de obtener el tamaño del teclado para evitar que mis campos de texto de esconderse detrás de él.

Me estoy poniendo una advertencia en Xcode -> UIKeyboardBoundsUserInfoKey está en desuso lo que no debo utilizar en lugar de obtener esta advertencia

¿Fue útil?

Solución

He jugado con la solución ofrecida anteriormente, pero todavía tenía problemas. Esto es lo que ocurrió con su lugar:

    - (void)keyboardWillShow:(NSNotification *)aNotification {
    [self moveTextViewForKeyboard:aNotification up:YES];
}

    - (void)keyboardWillHide:(NSNotification *)aNotification {
        [self moveTextViewForKeyboard:aNotification up:NO]; 
    }

- (void) moveTextViewForKeyboard:(NSNotification*)aNotification up: (BOOL) up{
NSDictionary* userInfo = [aNotification userInfo];

// Get animation info from 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];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

CGRect newFrame = textView.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];

newFrame.origin.y -= keyboardFrame.size.height * (up? 1 : -1);
textView.frame = newFrame;

[UIView commitAnimations];
}

Otros consejos

En la documentación para UIKeyboardBoundsUserInfoKey:

  

La clave para un objeto que contiene un NSValue CGRect que identifica los límites del rectángulo del teclado en coordenadas de ventana. Este valor es suficiente para obtener el tamaño del teclado. Si desea obtener el origen del teclado en la pantalla (antes o después de la animación) utilizar los valores obtenidos a partir del diccionario de información del usuario a través de las constantes UIKeyboardCenterBeginUserInfoKey o UIKeyboardCenterEndUserInfoKey. Usar la tecla UIKeyboardFrameBeginUserInfoKey o UIKeyboardFrameEndUserInfoKey lugar.

Apple recomienda implementar una rutina de conveniencia como este (que podrían ser implementadas como una categoría además de UIScreen):

+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view {
    UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window];
    return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil];
}

para recuperar propiedades de tamaño de marco del teclado ventana ajustados.

I tomó un enfoque diferente, que implica la comprobación de la orientación del dispositivo:

CGRect _keyboardEndFrame;
[[notification.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&_keyboardEndFrame];
CGFloat _keyboardHeight = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIDeviceOrientationPortraitUpsideDown) ? _keyboardEndFrame.size.height : _keyboardEndFrame.size.width;

Sólo tiene que utilizar este código:

//NSVale *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
//instead of Upper line we can use either next line or nextest line.
//NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey];
NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

Los siguientes arreglos de código en un problema en respuesta de Jay, que asume que UIKeyboardWillShowNotification no se disparará de nuevo cuando el teclado ya está presente.

Cuando la asignación con el / Teclado Chino Japonés, iOS dispara un UIKeyboardWillShowNotification adicional con el nuevo marco del teclado a pesar de que el teclado ya está presente, lo que lleva a la altura de la self.textView ser reducido por segunda vez en el código original.

Esto reduce self.textView a casi nada. Entonces se hace imposible recuperarse de este problema ya que sólo vamos a esperar que un solo UIKeyboardWillHideNotification la próxima vez que el teclado es despedido.

En lugar de restar / añadir altura a self.textView dependiendo de si se muestra / oculta como en el código original del teclado, el código siguiente justo calcula la posible altura máxima de self.textView después de restar la altura del teclado en pantalla.

Esto supone que self.textView se supone que debe llenar toda la vista del controlador de vista, y no hay otra subvista que necesita ser visible.

- (void)resizeTextViewWithKeyboardNotification:(NSNotification*)notif {

    NSDictionary* userInfo = [notif userInfo];
    NSTimeInterval animationDuration;
    UIViewAnimationCurve animationCurve;
    CGRect keyboardFrameInWindowsCoordinates;

    [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
    [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
    [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardFrameInWindowsCoordinates];

    [self resizeTextViewToAccommodateKeyboardFrame:keyboardFrameInWindowsCoordinates
                             withAnimationDuration:animationDuration
                                    animationCurve:animationCurve];

}

- (void)resizeTextViewToAccommodateKeyboardFrame:(CGRect)keyboardFrameInWindowsCoordinates
                           withAnimationDuration:(NSTimeInterval)duration
                                  animationCurve:(UIViewAnimationCurve)curve
{

    CGRect fullFrame = self.view.frame;

    CGRect keyboardFrameInViewCoordinates =
    [self.view convertRect:keyboardFrameInWindowsCoordinates fromView:nil];

    // Frame of the keyboard that intersects with the view. When keyboard is
    // dismissed, the keyboard frame still has width/height, although the origin
    // keeps the keyboard out of the screen.
    CGRect keyboardFrameVisibleOnScreen =
    CGRectIntersection(fullFrame, keyboardFrameInViewCoordinates);

    // Max frame availble for text view. Assign it to the full frame first
    CGRect newTextViewFrame = fullFrame;

    // Deduct the the height of any keyboard that's visible on screen from
    // the height of the text view
    newTextViewFrame.size.height -= keyboardFrameVisibleOnScreen.size.height;

    if (duration)
    {
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationCurve:curve];
    }

    // Adjust the size of the text view to the new one
    self.textView.frame = newTextViewFrame;

    if (duration)
    {
        [UIView commitAnimations];
    }

}

Además, no se olvide de registrar las notificaciones de teclado en viewDidLoad:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSNotificationCenter* notifCenter = [NSNotificationCenter defaultCenter];

    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillShowNotification object:nil];
    [notifCenter addObserver:self selector:@selector(resizeTextViewWithKeyboardNotification:) name:UIKeyboardWillHideNotification object:nil];
}

Sobre la división del código de cambio de tamaño en dos partes

La razón por la Textview cambiar el tamaño de código se divide en dos partes (resizeTextViewWithKeyboardNotification: y resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:) es fijar otro problema cuando las persiste teclado a través de un empuje de un controlador de vista a otro (ver ¿Cómo puedo detectar el teclado de iOS cuando permanece entre controladores? ).

Desde el teclado ya está presente antes de que se pulsa el controlador de vista, no hay notificaciones de teclado adicionales que se generan por iOS, y por lo tanto no hay manera de cambiar el tamaño del textView basado en las notificaciones de teclado.

El código anterior (así como el código original) que cambia de tamaño self.textView voluntad por lo tanto sólo el trabajo cuando se muestra el teclado después el punto de vista ha sido cargado.

Mi solución es crear un producto único que almacena las últimas coordenadas de teclado, y en - viewDidAppear: del viewController, llamada:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Resize the view if there's any keyboard presence before this
    // Only call in viewDidAppear as we are unable to convertRect properly
    // before view is shown
    [self resizeViewToAccommodateKeyboardFrame:[[UASKeyboard sharedKeyboard] keyboardFrame]
                         withAnimationDuration:0
                                animationCurve:0];
}

UASKeyboard es mi Singleton aquí. Lo ideal sería que deberíamos llamar a esto en - viewWillAppear:, sin embargo, en mi experiencia (al menos en IOS 6), el método convertRect:fromView: que necesitamos para el uso en resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve: no convierte correctamente el marco del teclado a las coordenadas de vista antes de la vista es totalmente visible.

Sólo tiene que utilizar la tecla UIKeyboardFrameBeginUserInfoKey o UIKeyboardFrameEndUserInfoKey en lugar de UIKeyboardBoundsUserInfoKey

@ Jason, que de código si bien, excepto por un punto.

En el momento en que en realidad no son nada animando y la vista simplemente se `pop' a su nueva size.height.

Tiene que especificar un estado del que animar. Una animación es una especie de (de estado) -. Lo> (a estado)

Por suerte hay un método muy conveniente para especificar el estado actual de la vista como la (de estado).

[UIView setAnimationBeginsFromCurrentState:YES];

Si se agrega que la línea derecha después de beginAnimations: contexto: su código funciona perfectamente.

- (CGSize)keyboardSize:(NSNotification *)aNotification {
    NSDictionary *info = [aNotification userInfo];
    NSValue *beginValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

    UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    CGSize keyboardSize;
    if ([UIKeyboardDidShowNotification isEqualToString:[aNotification name]]) {
        _screenOrientation = orientation;
        if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize = [beginValue CGRectValue].size;
        } else {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        }
    } else if ([UIKeyboardDidHideNotification isEqualToString:[aNotification name]]) {
        // We didn't rotate
        if (_screenOrientation == orientation) {
            if (UIDeviceOrientationIsPortrait(orientation)) {
                keyboardSize = [beginValue CGRectValue].size;
            } else {
                keyboardSize.height = [beginValue CGRectValue].size.width;
                keyboardSize.width = [beginValue CGRectValue].size.height;
            }
        // We rotated
        } else if (UIDeviceOrientationIsPortrait(orientation)) {
            keyboardSize.height = [beginValue CGRectValue].size.width;
            keyboardSize.width = [beginValue CGRectValue].size.height;
        } else {
            keyboardSize = [beginValue CGRectValue].size;
        }
    }


    return keyboardSize;
}

Su trabajó como esto

Esta es la restricción de la parte inferior botón Guardar

@IBOutlet weak var saveBtnBottom: NSLayoutConstraint!
@IBOutlet weak var nameText: UITextField!

Dentro de viewDidLoad

NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
nameText.delegate = self

Se trata de las funciones que necesitamos

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    nameText.resignFirstResponder()
    return true
}


@objc func keyBoardWillShow(notification: Notification){
    if let userInfo = notification.userInfo as? Dictionary<String, AnyObject>{
        let frame = userInfo[UIResponder.keyboardFrameEndUserInfoKey]
        let keyBoardRect = frame?.cgRectValue
        if let keyBoardHeight = keyBoardRect?.height {
            self.saveBtnBottom.constant = keyBoardHeight 

            UIView.animate(withDuration: 0.5, animations: {
                self.view.layoutIfNeeded()
            })
        }
    }
}

@objc func keyBoardWillHide(notification: Notification){
    self.saveBtnBottom.constant = 30.0
    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top