web-dev-qa-db-fra.com

UIKeyboardBoundsUserInfoKey est obsolète, que faut-il utiliser à la place?

Je travaille sur une application iPad utilisant 3.2 sdk. Je cherche à obtenir la taille du clavier pour éviter que mes champs de texte ne se cachent derrière. 

Je reçois un avertissement dans Xcode -> UIKeyboardBoundsUserInfoKey est obsolète. Que dois-je utiliser à la place pour ne pas obtenir cet avertissement?

49
Mikeware

J'ai joué avec la solution précédemment proposée mais j'avais toujours des problèmes. Voici ce que je suis venu à la place:

    - (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];
}
87
Jay

À partir de la documentation pour UIKeyboardBoundsUserInfoKey:

La clé d'un objet NSValue contenant un CGRect qui identifie le rectangle de délimitation du clavier dans les coordonnées de la fenêtre. Cette valeur est suffisante pour obtenir la taille du clavier. Si vous souhaitez afficher l’origine du clavier à l’écran (avant ou après l’animation), utilisez les valeurs obtenues du dictionnaire d’informations utilisateur par le biais des constantes UIKeyboardCenterBeginUserInfoKey ou UIKeyboardCenterEndUserInfoKey. Utilisez plutôt la clé UIKeyboardFrameBeginUserInfoKey ou UIKeyboardFrameEndUserInfoKey.

Apple recommande de mettre en œuvre une routine de commodité telle que celle-ci (qui pourrait être implémentée en tant que catégorie supplémentaire pour 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];
}

récupérer les propriétés de la taille du cadre du clavier ajustées par la fenêtre.

J'ai adopté une approche différente, qui consiste à vérifier l'orientation du périphérique:

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

Vous utilisez simplement ce code:

//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];
9
iOS_User

Le code suivant corrige un problème dans La réponse de Jay , qui suppose que UIKeyboardWillShowNotification ne se déclenchera pas à nouveau lorsque le clavier est déjà présent.

Lors de la frappe avec le clavier japonais/chinois, iOS déclenche une UIKeyboardWillShowNotification supplémentaire avec le nouveau cadre de clavier même si le clavier est déjà présent, ce qui entraîne une réduction de la hauteur de self.textView dans le code d'origine.

Cela réduit self.textView à presque rien. Il devient alors impossible de résoudre ce problème car nous n'attendrons plus qu'une seule variable UIKeyboardWillHideNotification lors de la prochaine utilisation du clavier.

Au lieu de soustraire/d'ajouter de la hauteur à self.textView selon que le clavier est affiché ou masqué comme dans le code d'origine, le code suivant calcule simplement la hauteur maximale possible pour self.textView après avoir soustrait la hauteur du clavier à l'écran.

Cela suppose que self.textView est censé remplir la totalité de la vue du contrôleur de vue et qu'aucune autre sous-vue ne doit être 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];
    }

}

De plus, n'oubliez pas d'enregistrer les notifications du clavier dans 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];
}

A propos de la scission du code de redimensionnement en deux parties

La raison pour laquelle le code de redimensionnement de textView est scindé en deux parties (resizeTextViewWithKeyboardNotification: et resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve:) est pour corriger un autre problème lorsque le clavier persiste lors du Push d'un contrôleur de vue à un autre (voir Comment détecter le clavier iOS lorsqu'il reste en place) entre contrôleurs? ).

Étant donné que le clavier est déjà présent avant que le contrôleur de vue ne soit poussé, iOS ne génère aucune autre notification de clavier, et donc aucun moyen de redimensionner la textView en fonction de ces notifications de clavier.

Le code ci-dessus (ainsi que le code d'origine) qui redimensionne self.textView ne fonctionnera donc que si le clavier est affiché après que la vue a été chargée.

Ma solution consiste à créer un singleton qui stocke les dernières coordonnées du clavier et, sur - viewDidAppear: du viewController, appelez:

- (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 est mon singleton ici. Idéalement, nous devrions appeler cela dans - viewWillAppear:. Toutefois, selon mon expérience (du moins sur iOS 6), la méthode convertRect:fromView: que nous devons utiliser dans resizeViewToAccommodateKeyboardFrame:withAnimationDuration:animationCurve: ne convertit pas correctement le cadre du clavier en coordonnées de vue avant que la vue ne soit entièrement visible.

3
junjie

Utilisez simplement la clé UIKeyboardFrameBeginUserInfoKey ou UIKeyboardFrameEndUserInfoKey au lieu de UIKeyboardBoundsUserInfoKey

2
Anand Mishra

@ Jason, vous code si tout va bien, sauf pour un point.

Pour le moment, vous n'animez rien et la vue "sautera" dans sa nouvelle taille.

Vous devez spécifier un état à partir duquel animer. Une animation est une sorte de (de l'état) -> (à l'état) chose.

Heureusement, il existe une méthode très pratique pour spécifier l'état actuel de la vue en tant que (à partir de l'état).

[UIView setAnimationBeginsFromCurrentState:YES];

Si vous ajoutez cette ligne juste après beginAnimations: context: votre code fonctionne parfaitement. 

1
Thomas
- (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;
}
1
0
karim

Ça a fonctionné comme ça

C'est la contrainte du bouton de sauvegarde en bas

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

Vue intérieureDidLoad

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

Ce sont les fonctions dont nous avons besoin

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()
    })
}
0
Mohammed Abunada