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?
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];
}
À 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;
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];
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];
}
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.
Utilisez simplement la clé UIKeyboardFrameBeginUserInfoKey
ou UIKeyboardFrameEndUserInfoKey
au lieu de UIKeyboardBoundsUserInfoKey
@ 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.
- (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;
}
Voici de bons détails http://i-phone-dev.blogspot.com/2012/01/different-way-to-show-keyboard-and.html
Ç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()
})
}