Comment ajouter un bouton `` Terminé '' au clavier du pavé numérique sous iOS

84

Ainsi, le clavier du pavé numérique n'est pas livré avec un bouton "Terminé" ou "Suivant" par défaut, je voudrais donc en ajouter un. Dans iOS 6 et les versions antérieures, il y avait quelques astuces pour ajouter un bouton au clavier, mais elles ne semblent pas fonctionner sous iOS 7.

Je m'abonne d'abord au clavier affichant la notification

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

Ensuite, j'essaye d'ajouter un bouton lorsque le clavier apparaît:

- (void)keyboardWillShow:(NSNotification *)note 
{
    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
    doneButton.frame = CGRectMake(0, 50, 106, 53);
    doneButton.adjustsImageWhenHighlighted = NO;
    [doneButton setTitle:@"Done" forState:UIControlStateNormal];
    [doneButton addTarget:self action:@selector(dismissKeyboard) forControlEvents:UIControlEventTouchUpInside];

    // locate keyboard view
    UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView* keyboard;
    for(int i=0; i<[tempWindow.subviews count]; i++) 
    {
        keyboard = [tempWindow.subviews objectAtIndex:i];
        // keyboard view found; add the custom button to it
        if([[keyboard description] hasPrefix:@"UIKeyboard"] == YES)
        [keyboard addSubview:doneButton];
    }
}

Mais la boucle for ne s'exécute pas car elle ne trouve aucune sous-vue. Aucune suggestion? Je n'ai pas trouvé de solution pour iOS7, alors y a-t-il une manière différente de le faire?

Edit: Merci pour toutes les suggestions pour les barres d'outils, mais je préfère ne pas suivre cette voie car je manque d'espace (et c'est un peu moche).

George McKibbin
la source
Vous avez essayé ce post? neoos.ch/blog/…
Anil
@Anil Cette façon de personnaliser UIKeyboard est interdite par Apple.
βhargavḯ
Vérifiez avec UIKeyboardDidShowNotification.
Praveen Matanam
essayez ceci github.com/simonbs/BSKeyboardControls
the1pawan
2
Je ne veux pas vraiment ajouter de barre d'outils, je veux mettre le bouton directement sur le clavier.
George McKibbin

Réponses:

26

Il s'agit d'un moyen simple de projeter un bouton terminé dans le clavier numérique iOS7. Dans la méthode déléguée ci-dessous de UITextField, ajoutez une notification pour l'affichage du clavier.

-(void)textFieldDidBeginEditing:(UITextField *)textField {

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];
}

Maintenant, implémentez la méthode keyboardWillShowcomme ci-dessous. Ici, nous devons faire très attention à iOS7.

- (void)keyboardWillShow:(NSNotification *)note {
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:@"doneButtonNormal.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:@"doneButtonPressed.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
    dispatch_async(dispatch_get_main_queue(), ^{
        UIView *keyboardView = [[[[[UIApplication sharedApplication] windows] lastObject] subviews] firstObject];
        [doneButton setFrame:CGRectMake(0, keyboardView.frame.size.height - 53, 106, 53)];
        [keyboardView addSubview:doneButton];
        [keyboardView bringSubviewToFront:doneButton];

        [UIView animateWithDuration:[[note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue]-.02
                              delay:.0
                            options:[[note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]
                         animations:^{
                             self.view.frame = CGRectOffset(self.view.frame, 0, 0);
                         } completion:nil];
    });
}else {
    // locate keyboard view
    dispatch_async(dispatch_get_main_queue(), ^{
        UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
        UIView* keyboard;
        for(int i=0; i<[tempWindow.subviews count]; i++) {
            keyboard = [tempWindow.subviews objectAtIndex:i];
            // keyboard view found; add the custom button to it
            if([[keyboard description] hasPrefix:@"UIKeyboard"] == YES)
                [keyboard addSubview:doneButton];
        }
    });
  }
}

Ajoutez maintenant cette macro à l'en-tête approprié pour détecter le SYSTEM_VERSION

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

Balram Tiwari
la source
1
Merci, c'est ce que je voulais :) Malheureusement, s'il y avait déjà un clavier à l'écran et que vous passez ensuite à un champ qui nécessite un clavier numérique, keyBoardWillShow n'est pas appelé. Mais merci, un pas dans la bonne direction haha.
George McKibbin
SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO pourquoi pas NSFoundationVersionNumber> NSFoundationVersionNumber_iOS_6_0? Et je le teste, NSFoundationVersionNumber_iOS_5_0 est meilleur
govo
dispatch_async n'est pas la méthode la plus fiable pour pirater le clavier ici. :(
pronebird
7
dans iOS8, ce bouton terminé ne se cache pas, après le rejet du clavier.
Hemant Chittora
2
Cette réponse, quoique intelligente, était vouée à l'échec.
SwiftArchitect
187

L'approche beaucoup plus sûre consiste à utiliser un UIToolBaravec DoneButton as inputAccessoryView.


Exemple de code:

UIToolbar *keyboardDoneButtonView = [[UIToolbar alloc] init];
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                               style:UIBarButtonItemStyleBordered target:self
                                                              action:@selector(doneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
txtField.inputAccessoryView = keyboardDoneButtonView;

Votre -doneClickedméthode devrait ressembler à ceci:

- (IBAction)doneClicked:(id)sender
{
    NSLog(@"Done Clicked.");
    [self.view endEditing:YES];
}

Exemple de code Swift:

let keyboardDoneButtonView = UIToolbar.init()
keyboardDoneButtonView.sizeToFit()
let doneButton = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.Done, 
                                                   target: self, 
                                                   action: Selector("doneClicked:")))    

keyboardDoneButtonView.items = [doneButton]
textFieldInput.inputAccessoryView = keyboardDoneButtonView

Votre -doneClickedméthode devrait ressembler à ceci:

func doneClicked(sender: AnyObject) {
  self.view.endEditing(true)
}
Bhavin
la source
Je devrai peut-être finir par faire ça. Je n'aime pas vraiment la place que cela prend.
George McKibbin
3
@GeorgeMcKibbin: L'espace ne devrait pas être le problème ici car il ne prendra cet espace que pendant que vous tapez. De plus, selon moi, cette approche est bien meilleure que de déranger le clavier que Apple n'aime généralement pas.
Bhavin
Lorsque je fais cela, je n'obtiens que la barre d'outils tout en bas de mon écran et le clavier n'apparaît plus. Pensées?
Chris
excellente réponse, juste une friandise, arrayWithObjects est tacitement obsolète en faveur des littéraux: [NSArray arrayWithObjects: doneButton, nil] => @ [doneButton]
Austin
1
à partir d'iOS 8.0 UIBarButtonItemStyleBorderedest une utilisation obsolète UIBarButtonItemStyleDoneouUIBarButtonItemStylePlain
Nazir
131

Une manière encore plus simple:

Swift 3.0 et supérieur :

func addDoneButton() {
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace,
        target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done,
        target: view, action: #selector(UIView.endEditing(_:)))
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    textField.inputAccessoryView = keyboardToolbar
}

Swift 2.3 et inférieur :

func addDoneButton() {
    let keyboardToolbar = UIToolbar()
    keyboardToolbar.sizeToFit()
    let flexBarButton = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace,
        target: nil, action: nil)
    let doneBarButton = UIBarButtonItem(barButtonSystemItem: .Done,
        target: view, action: #selector(UIView.endEditing(_:)))
    keyboardToolbar.items = [flexBarButton, doneBarButton]
    textField.inputAccessoryView = keyboardToolbar
}

Objectif C :

- (void)addDoneButton {
    UIToolbar* keyboardToolbar = [[UIToolbar alloc] init];
    [keyboardToolbar sizeToFit];
    UIBarButtonItem *flexBarButton = [[UIBarButtonItem alloc]
    initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
    target:nil action:nil];
    UIBarButtonItem *doneBarButton = [[UIBarButtonItem alloc]
    initWithBarButtonSystemItem:UIBarButtonSystemItemDone
    target:self.view action:@selector(endEditing:)];
    keyboardToolbar.items = @[flexBarButton, doneBarButton];
    self.textField.inputAccessoryView = keyboardToolbar;
}

ÉDITER:

J'ai créé une bibliothèque utile appelée DCKit , qui contient déjà la barre d'outils prête à l'emploi :

Barre d'outils terminée au-dessus du clavier sous iOS (avec l'utilisation de la bibliothèque DCKit)

Il a également de nombreuses autres fonctionnalités intéressantes.

Andrey Gordeev
la source
1
Il me semble que vous avez ajouté un bouton de barre flexible à la réponse de Bhavin d'il y a 1 an en tant que nouvelle réponse afin que je puisse voir pourquoi quelqu'un a voté à la baisse. Peut-être que j'ai raté quelque chose ici aussi?
Mark McCorkle
2
Oui, je n'utilise pas initWithTitle:@"Done", j'utilise à la initWithBarButtonSystemItem:UIBarButtonSystemItemDoneplace. Cela renverra le bouton standard de la barre Terminé d'Apple. De plus, il sera déjà localisé
Andrey Gordeev
3
Cela devrait être ajouté comme une amélioration (commentaire) à la réponse précédemment correcte IMO ou attendre des votes à la baisse. Une nouvelle réponse devrait impliquer une approche différente de la question initiale, et non une amélioration d'une question existante. Néanmoins, merci pour l'amélioration. ;-)
Mark McCorkle
4
Non je ne pense pas. Les commentaires ne sont pas censés être utilisés pour écrire du code :)
Andrey Gordeev
13

Il suffit de s'appuyer sur les réponses ci-dessus avec la version Swift puisque j'ai dû la traduire:

   @IBOutlet weak var numberTextField: UITextField!

    override func viewDidLoad() {
        addDoneButtonTo(numberTextField)
    }

    // MARK: Done for numberTextField

    private func addDoneButtonTo(textField: UITextField) {
        let flexBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
        let doneBarButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "didTapDone:")
        let keyboardToolbar = UIToolbar()
        keyboardToolbar.sizeToFit()
        keyboardToolbar.items = [flexBarButton, doneBarButton]
        textField.inputAccessoryView = keyboardToolbar
    }

    func didTapDone(sender: AnyObject?) {
        numberTextField.endEditing(true)
    }
Arnaud
la source
3

Vous pouvez utiliser

myTextField.inputAccessoryView = _inputView;

la vue d'accessoire d'entrée est une vue qui vient toujours sur le clavier et qui est rejetée avec le [textfield resignFirstResponder]

placez donela vue d'entrée et exécutez le premier répondeur des champs de texte.

Himanshu Gupta
la source
2

Juste utiliser

yourTextField.inputAccessoryView

j'espère que tu m'aides

alvarodoune
la source
2
enter code here

1. register the controller to the notification

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // Keyboard events
    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillShow:)
                                             name:UIKeyboardWillShowNotification
                                           object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(keyboardWillHide:)
                                             name:UIKeyboardWillHideNotification
                                           object:nil];
}

2. don't forget to remove the controller from the notification centre

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self.view endEditing:YES];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

3. implement keyboard notification handlers

- (void)keyboardWillShow:(NSNotification *)notification {

// create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(0, 107, 106, 53);
    [doneButton setTitle:@"Done" forState:UIControlStateNormal];
    [doneButton addTarget:self  action:@selector(doneButton:)forControlEvents:UIControlEventTouchUpInside];

// save the reference to the button in order to use it in keyboardWillHide method
   self.donekeyBoardBtn = doneButton;

// to my mind no need to search for subviews
   UIWindow *windowContainigKeyboard = [[[UIApplication sharedApplication] windows]  lastObject];
   [windowContainigKeyboard addSubview:self.donekeyBoardBtn];
   self.donekeyBoardBtn.frame = CGRectMake(0., CGRectGetHeight(w.frame) -  CGRectGetHeight(self.donekeyBoardBtn.frame), CGRectGetWidth(self.donekeyBoardBtn.frame), CGRectGetHeight(self.donekeyBoardBtn.frame));
}

- (void)keyboardWillHide:(NSNotification *)notification {

    [self.donekeyBoardBtn removeFromSuperview];
}

4. implement done button action

- (void)doneButton:(id)sender{
   // add needed implementation
      [self.view endEditing:YES]; 
}
Loloa
la source
J'ai mis en œuvre votre réponse de manière très similaire à ce que je dois faire. Merci. Mais le bouton ne vient pas comme un objet animé, lorsque le clavier s'affiche.
Arpit B Parekh
1

Vous devez détecter si vous êtes sur un téléphone ou un iPad puisque l'iPad implémente une touche de retour sur le pavé numérique

user3288300
la source