J'essaie d'obtenir un comportement de positionnement similaire à la barre de saisie de texte inférieure dans l'application Messages d'Apple.
J'ai essayé de nombreuses approches, recherché haut et bas et il y a beaucoup de questions similaires mais aucune n'a été satisfaisante.
Spécifier:
UIToolbar
en bas de la vueLes solutions proposées:
Cette solution ne répond pas à un cas particulier de la deuxième exigence ( la barre d'outils est de suivre le clavier tel que le clavier apparaît et disparaît ):
UIScrollViewKeyboardDismissMode
a été introduit. Il permet un geste interactif pour ignorer le clavier. Au fur et à mesure que l'utilisateur parcourt le bord supérieur du clavier, le cadre du clavier suit progressivement. Cette solution ne fait rien pour s'adapter à ce comportement et laisse simplement la barre d'outils bloquée à sa position animée.De plus, cette solution ne répond pas non plus à un cas particulier de la troisième condition ( la barre d'outils doit rester au-dessus du clavier lorsque le clavier est visible ) :
Un autre problème avec cette solution:
Prochaine solution proposée:
UIResponder
de inputAccessoryView
Cette solution semble être la manière Apple destinée à prendre en charge ce type de comportement, car elle résout tous les défauts de l'animation manuelle de la barre d'outils. Mais cette solution manque complètement la quatrième condition ( lorsque le clavier est masqué, la barre d'outils reste ("ancrée") en bas de la vue ).
Il semble que la solution consiste à utiliser le UIResponder
de inputAccessoryView
, mais en faisant en sorte que le inputAccessoryView
ne se déplace pas sous la vue. Je cherche du code propre pour accomplir cela. Il y a des tentatives élaborées, presque nobles ailleurs, mais comme mentionné, elles ne répondent pas aux exigences.
Dans mon cas particulier, je cherche à utiliser la barre d'outils de UINavigationController
qui entraîne des problèmes supplémentaires car ce n'est pas un comportement prévu pour UINavigationController
. Peu importe, je suis prêt à introduire des correctifs hacky pour y parvenir.
On vient de me montrer "la" solution par Jason Foreman (@threeve). Sur votre contrôleur de vue (oui, contrôleur de vue), ajoutez inputAccessoryView:
et retournez la vue que vous souhaitez ancrer en bas et déplacez-vous avec le clavier. Ça marche juste. La vue n'a pas besoin d'être dans votre hiérarchie de vues, elle sera insérée automatiquement par le contrôleur de vue.
edit: implémentez également canBecomeFirstResponder et retournez YES (comme l'a noté Max Seelemann). reloadInputViews peut également être utile.
La solution susmentionnée de Jonathan Badeen solution a fonctionné pour moi. Voici le code de Arik montrant comment l'implémenter (cela devrait aller dans votre contrôleur de vue approprié):
- (BOOL)canBecomeFirstResponder{
return YES;
}
- (UIView *)inputAccessoryView{
return self.inputAccessoryToolbar;
// where inputAccessoryToolbar is your keyboard accessory view
}
Pour ceux qui recherchent Swift version:
Connectez votre barre d'outils (dans mon cas 'myToolBar
') à votre contrôleur de vue. Remplacez ensuite la méthode canBecomeFirstResponder
et remplacez la variable getter inputAccessoryView
. N'oubliez pas non plus d'ajouter la self.myToolBar.removeFromSuperview()
sinon xcode se plaindra.
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()
}
}
Il existe une excellente solution open-source facile à implémenter de la part des bons employés de Slack: SlackTextViewController.
Voici comment implémenter une vue avec une barre d'outils ancrée en quatre étapes:
Créez un MessageViewController
qui hérite de SLKTextViewController
, pas besoin d'écrire plus de code que celui-ci:
import Foundation
import UIKit
class MessageViewController: SLKTextViewController {
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
}
Accessoires à l'équipe de Slack pour l'extraction d'un pod aussi utile.
Je sais donc que c'est un ancien message et je ne sais pas si vous avez résolu cela ou non, mais j'ai trouvé un moyen de faire fonctionner cela. Je crois qu'il y a un bogue dans inputAccessoryView, mais j'ai créé une solution hacky pour se comporter comme le fait l'application de messages. Je pense avoir fourni tout le code nécessaire pour implémenter le travail. Je vais essayer de créer un article de blog plus approprié dans un proche avenir, avec une description plus approfondie de mes résultats. Toutes les questions, faites-le moi savoir.
@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];
}
////////////////////////////////////////////////////////////////////////////////////////////////////