Cómo agregar un botón 'Listo' al teclado numérico en iOS


84

Por lo tanto, el teclado numérico no viene con un botón 'Listo' o 'Siguiente' por defecto, así que me gustaría agregar uno. En iOS 6 y versiones anteriores, había algunos trucos para agregar un botón al teclado, pero parece que no funcionan en iOS 7.

Primero me suscribo al teclado que muestra la notificación

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

Luego trato de agregar un botón cuando aparece el teclado:

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

Pero el bucle for no se ejecuta porque no encuentra ninguna subvista. ¿Alguna sugerencia? No pude encontrar ninguna solución para iOS7, así que, ¿se supone que debo hacer esto de otra manera?

Editar: Gracias por todas las sugerencias para los chicos de las barras de herramientas, pero prefiero no seguir ese camino ya que tengo poco espacio (y es algo feo).


¿Has probado esta publicación? neoos.ch/blog/…
Anil

@Anil Apple prohíbe esa forma de personalizar UIKeyboard.
βhargavḯ

Consulte con UIKeyboardDidShowNotification.
Praveen Matanam


2
Realmente no quiero agregar una barra de herramientas, quiero poner el botón directamente en el teclado.
George McKibbin

Respuestas:


26

Esta es una forma sencilla de proyectar un botón hecho en el teclado numérico de iOS7. En el siguiente método de delegado de UITextField, agregue una notificación para mostrar el teclado.

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

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

Ahora implemente el método de la keyboardWillShowsiguiente manera. Aquí debemos tener especial cuidado con 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];
        }
    });
  }
}

Ahora agregue esta macro al encabezado adecuado para detectar SYSTEM_VERSION

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


1
Gracias, esto es lo que quería :) Desafortunadamente, si ya había un teclado en la pantalla y luego cambia a un campo que necesita un teclado numérico, entonces no se llama a keyBoardWillShow. Pero gracias, un paso en la dirección correcta jaja.
George McKibbin

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO ¿por qué no NSFoundationVersionNumber> NSFoundationVersionNumber_iOS_6_0? Y lo pruebo, NSFoundationVersionNumber_iOS_5_0 es mejor
govo

dispatch_async no es el método más confiable para hackear el teclado aquí. :(
pronebird

7
en iOS8, este botón hecho no se oculta, después de la salida del teclado.
Hemant Chittora

2
Esta respuesta, aunque inteligente, estaba destinada a romperse.
SwiftArchitect

187

El enfoque mucho más seguro es usar un UIToolBarcon DoneButton como inputAccessoryView.


Código de muestra :

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;

Tu -doneClickedmétodo debería verse así:

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

Código de muestra 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

Tu -doneClickedmétodo debería verse así:

func doneClicked(sender: AnyObject) {
  self.view.endEditing(true)
}

Puede que tenga que terminar haciendo esto. Realmente no me gusta cuánto espacio ocupa.
George McKibbin

3
@GeorgeMcKibbin: El espacio no debería ser el problema aquí, ya que ocupará ese espacio solo mientras está escribiendo. Además, en mi opinión, este enfoque es mucho mejor que estropear el teclado que normalmente a Apple no le gusta.
Bhavin

Cuando hago esto, solo aparece la barra de herramientas en la parte inferior de la pantalla y el teclado ya no aparece. Pensamientos
Chris

gran respuesta, solo un tidbit, arrayWithObjects está en desuso tácitamente en favor de los literales: [NSArray arrayWithObjects: doneButton, nil] => @ [doneButton]
Austin

1
de iOS 8.0 UIBarButtonItemStyleBorderedestá en desuso UIBarButtonItemStyleDoneoUIBarButtonItemStylePlain
Nazir

131

Manera aún más fácil:

Swift 3.0 y superior :

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 y versiones anteriores :

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
}

Objetivo 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;
}

EDITAR:

He creado una biblioteca útil llamada DCKit , que ya tiene la barra de herramientas lista para usar :

Hecho barra de herramientas encima del teclado en iOS (con el uso de la biblioteca DCKit)

También tiene muchas otras características interesantes.


1
Me parece que agregó un botón de barra flexible a la respuesta de Bhavin de hace 1 año como una nueva respuesta para poder ver por qué alguien lo rechazó. ¿Quizás me perdí algo aquí también?
Mark McCorkle

2
Sí, no uso initWithTitle:@"Done", uso initWithBarButtonSystemItem:UIBarButtonSystemItemDoneen su lugar. Esto devolverá el botón de la barra Listo estándar de Apple. Además, ya estará localizado
Andrey Gordeev

3
Esto debe agregarse como una mejora (comentario) a la respuesta correcta previamente OMI o esperar votos negativos. Una nueva respuesta debe implicar un enfoque diferente a la pregunta original, no una mejora a una pregunta existente. No obstante, gracias por la mejora. ;-)
Mark McCorkle

4
No, no lo creo. No se supone que los comentarios se utilicen para escribir código :)
Andrey Gordeev

13

Basándome en las respuestas anteriores con la versión Swift, ya que tuve que traducirlo:

   @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)
    }

3

Puedes usar

myTextField.inputAccessoryView = _inputView;

La vista de accesorios de entrada es una vista que aparece siempre en el teclado y se cierra con el [textfield resignFirstResponder]

coloque donesobre la vista de entrada y realice el primer respondedor de los campos de texto.



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]; 
}

Implementé tu respuesta de manera muy similar a lo que tengo que hacer. Gracias. Pero el botón no viene como un objeto animado, cuando se muestra el teclado.
Arpit B Parekh

1

Necesita detectar si está en un teléfono o iPad, ya que el iPad implementa una tecla de retorno en el teclado "numérico".


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.