Alignez par programme une barre d'outils sur le clavier de l'iPhone

94

Dans plusieurs cas, je souhaite ajouter une barre d'outils en haut du clavier de l'iPhone (comme dans iPhone Safari lorsque vous naviguez dans des éléments de formulaire, par exemple).

Actuellement, je spécifie le rectangle de la barre d'outils avec des constantes, mais parce que d'autres éléments de l'interface sont en flux - les barres d'outils et les barres de navigation en haut de l'écran - chaque fois que nous faisons un changement mineur d'interface, la barre d'outils se désaligne.

Existe-t-il un moyen de déterminer par programme la position du clavier par rapport à la vue actuelle?

Rob Drimmie
la source

Réponses:

142

Depuis iOS 3.2, il existe une nouvelle façon d'obtenir cet effet:

UITextFieldset UITextViewsavoir une inputAccessoryViewpropriété, que vous pouvez définir sur n'importe quelle vue, qui est automatiquement affichée au-dessus et animée avec le clavier.

Notez que la vue que vous utilisez ne doit pas être dans la hiérarchie des vues ailleurs, ni que vous ne devez l'ajouter à une vue supervisée, cela est fait pour vous.

tonklon
la source
Laisse-moi essayer . Bien que cela ait l'air de la meilleure façon.
harshalb
Sensationnel. Quelle trouvaille! Merci (je l'ai fait à la dure et c'est
compliqué
1
J'ai une UIToolbar avec un UITextField à l'intérieur de l'un de ses éléments de bouton de barre, mais bien que j'aie défini l'entrée textFields inputAccessoryView sur cette barre d'outils lors de la première pression, la barre d'outils monte mais aucun clavier n'apparaît. Dans la deuxième pression, le clavier apparaît avec la barre d'outils avez une idée à ce sujet?
Ugur Kumru
Mais comment ajouter une barre d'outils sur UIWebView? :(
Dmitry
Je l'ai fait en remplaçant les boutons de la barre d'outils UIWebView standard (le même code que pour le supprimer).
Dmitry
72

Donc en gros:

Dans la méthode init:

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];

Et puis avoir des méthodes mentionnées ci-dessus pour ajuster la position de la barre:

-(void) keyboardWillShow:(NSNotification *) note
{
    CGRect r  = bar.frame, t;
    [[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &t];
    r.origin.y -=  t.size.height;
    bar.frame = r;
}

Pourrait le rendre joli en animant le changement de position en l'enveloppant dans

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];
//...
    [UIView commitAnimations];

la source
J'ai fouillé mes vieux trucs ce matin et j'ai remarqué que c'était une réponse bien meilleure et la plus complète. Merci!
Rob Drimmie
Cette réponse est toujours d'actualité plus d'un an plus tard. Cela m'a aidé à surmonter la bosse lors du développement de quelque chose lié à cela.
james_womack
2
Juste un avertissement aux personnes qui trébuchent sur cette question maintenant: la UIKeyboardBoundsUserInfoKey est désormais obsolète dans iPhone OS 3.2. Il y en a d'autres similaires, comme ceux UIKeyboardFrameBeginUserInfoKeyqui donnent les mêmes informations.
Stephen Darlington le
9
Il existe même une nouvelle façon de faire mieux dans iOS3.2 la propriété inputAccessoryView sur UITextField et UITextView.
tonklon
6
Cette réponse a aidé une tonne mais est un peu datée. Vous devez utiliser UIKeyboardFrameEndUserInfoKeypour obtenir le cadre final (en coordiantes d'écran) du clavier. Vous pouvez également utiliser UIKeyboardAnimationDurationUserInfoKeyet UIKeyboardAnimationCurveUserInfoKeypour obtenir le reste des paramètres dont vous avez besoin pour correspondre exactement au comportement du clavier.
Dave Peck
60

Ceci est basé sur la réponse existante de tonklon - j'ajoute simplement un extrait de code qui montre une barre d'outils noire semi-transparente sur le dessus du clavier, ainsi qu'un bouton "terminé" à droite:

UIToolbar *toolbar = [[[UIToolbar alloc] init] autorelease];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];

UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(resignKeyboard)];

NSArray *itemsArray = [NSArray arrayWithObjects:flexButton, doneButton, nil];

[flexButton release];
[doneButton release];
[toolbar setItems:itemsArray];

[aTextField setInputAccessoryView:toolbar];

et le -resignKeyboardressemble à:

-(void)resignKeyboard {
  [aTextField resignFirstResponder];
}

J'espère que cela aide quelqu'un.

phi
la source
2
Juste ajouter un petit commentaire sur la mise en place du prochain précédent. UISegmentedControl * segmentControl = [[UISegmentedControl alloc] initWithItems: [NSArray arrayWithObjects: @ "Précédent", @ "Suivant", nil]]; [segmentControl setSegmentedControlStyle: UISegmentedControlStyleBar]; [segmentControl addTarget: auto-action: @selector (nextPrevious :) forControlEvents: UIControlEventValueChanged];
Trausti Thor
1
Un ajout au commentaire de @ TraustiThor: Vous devez envelopper le contrôle segmenté dans un UIBarButtonItem pour l'ajouter à la barre d'outils.
Tim Büthe
Excellent - c'est tout le code dont j'avais besoin. Merci d'avoir posté :)
Stretch le
Mais qu'en est-il de UIWebView? Comment y ajouter une barre d'outils?
Dmitry
24

Si vous vous inscrivez aux notifications clavier, c'est-à-dire UIKeyboardWillShowNotification UIKeyboardWillHideNotification, etc., la notification que vous recevrez contiendra les limites du clavier dans le userInfodict ( UIKeyboardBoundsUserInfoKey).

Voir la UIWindowréférence de la classe.

amrox
la source
16

Dans la version 3.0 et supérieure, vous pouvez obtenir la durée et la courbe de l'animation à partir du userInfodictionnaire des notifications.

par exemple, pour animer la taille de la vue pour faire de la place pour le clavier, enregistrez-vous pour le UIKeyboardWillShowNotificationet faites quelque chose comme ce qui suit:

- (void)keyboardWillShow:(NSNotification *)notification
{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
    [UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];

    CGRect frame = self.view.frame;
    frame.size.height -= [[[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size.height;
    self.view.frame = frame;

    [UIView commitAnimations];
}

Faites une animation similaire pour UIKeyboardWillHideNotification.

David Beck
la source
Cela semble être une meilleure façon de le faire sur le SDK 3.0, merci d'avoir posté!
Hua-Ying le
Merci pour le code. Cela aide beaucoup. Mais lorsque je configure mon UITextView pour devenir le premier répondeur dans le viewDidLoad, l'UIToolBar ne bouge pas avec le redimensionnement de self.view. Avez-vous une idée pourquoi?
RyanJM
1
@RyanJM: devenirFirstResponder et resignFirstResponder ont un comportement étrange lorsque la vue est hors écran. Vous devriez plutôt appeler devientFirstResponder à partir de votre méthode viewWillAppear.
David Beck
0

Créez cette méthode et appelez-la sur ViewWillLoad:

        - (void) keyboardToolbarSetup
{
    if(self.keyboardToolbar==nil)
        {
        self.keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];

        UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(anyAction)];

        UIBarButtonItem *extraSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];

        UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(anyOtherAction)];


        NSArray *toolbarButtons = [[NSArray alloc]initWithObjects:cancelButton,extraSpace,doneButton, nil];

        [self.keyboardToolbar setItems:toolbarButtons];

        self.myTextView.inputAccessoryView=self.keyboardToolbar;
        }
}
Juan Sebastián López
la source
-3

Il n'y a aucun moyen (AFAIK) d'obtenir les dimensions de la vue du clavier. Il est cependant constant, du moins dans toutes les versions d'iPhone jusqu'à présent.

Si vous calculez la position de la barre d'outils comme un décalage par rapport au BAS de votre vue et que vous tenez compte de la taille de votre vue, vous ne devriez pas avoir à vous soucier de la présence ou non d'une barre de navigation.

Par exemple

#define KEYBOARD_HEIGHT 240 // example - can't remember the exact size
#define TOOLBAR_HEIGHT 30

toolBarRect.origin.y = viewRect.size.height - KEYBOARD_HEIGHT - TOOLBAR_HEIGHT;

// move toolbar either directly or with an animation

Au lieu d'une définition, vous pouvez facilement créer une keyboardHeightfonction qui renvoie la taille en fonction de l'affichage du clavier et déplacer ce positionnement de la barre d'outils dans une fonction distincte qui réorganise votre disposition.

Cela peut également dépendre de l'endroit où vous effectuez ce positionnement car il est possible que la taille de votre vue puisse changer entre le chargement et l'affichage en fonction de la configuration de votre barre de navigation. Je crois que le meilleur endroit pour le faire serait en vueWillAppear.

Andrew Grant
la source
Cela a très bien fonctionné, merci! Jusqu'à présent, j'ai fait ce calcul dans le sélecteur déclenché par UIKeyboardDidShowNotification. Je n'ai testé que dans quelques endroits, mais cela semble être un bon endroit.
Rob Drimmie
Depuis la version 5.0, la taille du clavier n'est plus statique.
Alastair Stuart