Как показать кнопку "Готово" на iPhone number pad

на цифровой клавиатуре нет кнопки "Готово". Когда пользователь заканчивает вводить числовую информацию в текстовое поле, как я могу заставить цифровую панель исчезнуть?

Я мог бы получить кнопку "сделать" с помощью клавиатуры по умолчанию, но тогда пользователям придется переключаться на цифровые клавиши для ввода цифр. Есть ли способ показать кнопку "Готово" на цифровой клавиатуре?

21 ответов


другое решение. Идеально подходит, если на экране есть другие текстовые поля, отличные от цифровых.

inputAccessoryView

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
    numberToolbar.barStyle = UIBarStyleBlackTranslucent;
    numberToolbar.items = @[[[UIBarButtonItem alloc]initWithTitle:@"Cancel" style:UIBarButtonItemStyleBordered target:self action:@selector(cancelNumberPad)],
                         [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
                         [[UIBarButtonItem alloc]initWithTitle:@"Apply" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithNumberPad)]];
    [numberToolbar sizeToFit];
    numberTextField.inputAccessoryView = numberToolbar;
}

-(void)cancelNumberPad{
    [numberTextField resignFirstResponder];
    numberTextField.text = @"";
}

-(void)doneWithNumberPad{
    NSString *numberFromTheKeyboard = numberTextField.text;
    [numberTextField resignFirstResponder];
}

вот адаптация ответа Люды для Swift:

в объявлении вашего подкласса UIViewController поставьте

let numberToolbar: UIToolbar = UIToolbar()

В ViewDidLoad ставим:

    numberToolbar.barStyle = UIBarStyle.BlackTranslucent
    numberToolbar.items=[
        UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Bordered, target: self, action: "hoopla"),
        UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil),
        UIBarButtonItem(title: "Apply", style: UIBarButtonItemStyle.Bordered, target: self, action: "boopla")
    ]

    numberToolbar.sizeToFit()

    textField.inputAccessoryView = numberToolbar //do it for every relevant textfield if there are more than one 

и добавьте функции hoopla и hoopla (не стесняйтесь выбирать другие имена, просто измените имена селекторов в ViewDidLoad соответственно

func boopla () {
    textField.resignFirstResponder()
}

func hoopla () {
    textField.text=""
    textField.resignFirstResponder()
}

трюк, который я видел, используется, чтобы сделать пользовательскую прозрачную кнопку размером всего представления, а затем в своем методе щелчка, чтобы текстовое поле ушло в отставку первым ответчиком. Таким образом, пользователь может нажать в любом месте за пределами поля, чтобы закрыть клавиатуру.


решением UIKeyboardTypeNumberPad и отсутствует ключ возврата отлично работает, но только если на экране нет других текстовых полей без номера.

Я взял этот код и превратил его в UIViewController, который вы можете просто подкласс, чтобы заставить цифровые панели работать. Вам нужно будет получить значки из приведенной выше ссылки.

NumberPadViewController.h:

#import <UIKit/UIKit.h>

@interface NumberPadViewController : UIViewController {
    UIImage *numberPadDoneImageNormal;
    UIImage *numberPadDoneImageHighlighted;
    UIButton *numberPadDoneButton;
}

@property (nonatomic, retain) UIImage *numberPadDoneImageNormal;
@property (nonatomic, retain) UIImage *numberPadDoneImageHighlighted;
@property (nonatomic, retain) UIButton *numberPadDoneButton;

- (IBAction)numberPadDoneButton:(id)sender;

@end

и NumberPadViewController.м:

#import "NumberPadViewController.h"

@implementation NumberPadViewController

@synthesize numberPadDoneImageNormal;
@synthesize numberPadDoneImageHighlighted;
@synthesize numberPadDoneButton;

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    if ([super initWithNibName:nibName bundle:nibBundle] == nil)
        return nil;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.0) {
        self.numberPadDoneImageNormal = [UIImage imageNamed:@"DoneUp3.png"];
        self.numberPadDoneImageHighlighted = [UIImage imageNamed:@"DoneDown3.png"];
    } else {        
        self.numberPadDoneImageNormal = [UIImage imageNamed:@"DoneUp.png"];
        self.numberPadDoneImageHighlighted = [UIImage imageNamed:@"DoneDown.png"];
    }        
    return self;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    // Add listener for keyboard display events
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                    selector:@selector(keyboardDidShow:) 
                                                     name:UIKeyboardDidShowNotification 
                                                   object:nil];     
    } else {
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(keyboardWillShow:) 
                                                     name:UIKeyboardWillShowNotification 
                                                   object:nil];
    }

    // Add listener for all text fields starting to be edited
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(textFieldDidBeginEditing:)
                                                 name:UITextFieldTextDidBeginEditingNotification 
                                               object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
        [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                        name:UIKeyboardDidShowNotification 
                                                      object:nil];      
    } else {
        [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                        name:UIKeyboardWillShowNotification 
                                                      object:nil];
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                    name:UITextFieldTextDidBeginEditingNotification 
                                                  object:nil];
    [super viewWillDisappear:animated];
}

- (UIView *)findFirstResponderUnder:(UIView *)root {
    if (root.isFirstResponder)
        return root;    
    for (UIView *subView in root.subviews) {
        UIView *firstResponder = [self findFirstResponderUnder:subView];        
        if (firstResponder != nil)
            return firstResponder;
    }
    return nil;
}

- (UITextField *)findFirstResponderTextField {
    UIResponder *firstResponder = [self findFirstResponderUnder:[self.view window]];
    if (![firstResponder isKindOfClass:[UITextField class]])
        return nil;
    return (UITextField *)firstResponder;
}

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

    // Remove any previous button
    [self.numberPadDoneButton removeFromSuperview];
    self.numberPadDoneButton = nil;

    // Does the text field use a number pad?
    if (textField.keyboardType != UIKeyboardTypeNumberPad)
        return;

    // If there's no keyboard yet, don't do anything
    if ([[[UIApplication sharedApplication] windows] count] < 2)
        return;
    UIWindow *keyboardWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];

    // Create new custom button
    self.numberPadDoneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.numberPadDoneButton.frame = CGRectMake(0, 163, 106, 53);
    self.numberPadDoneButton.adjustsImageWhenHighlighted = FALSE;
    [self.numberPadDoneButton setImage:self.numberPadDoneImageNormal forState:UIControlStateNormal];
    [self.numberPadDoneButton setImage:self.numberPadDoneImageHighlighted forState:UIControlStateHighlighted];
    [self.numberPadDoneButton addTarget:self action:@selector(numberPadDoneButton:) forControlEvents:UIControlEventTouchUpInside];

    // Locate keyboard view and add button
    NSString *keyboardPrefix = [[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2 ? @"<UIPeripheralHost" : @"<UIKeyboard";
    for (UIView *subView in keyboardWindow.subviews) {
        if ([[subView description] hasPrefix:keyboardPrefix]) {
            [subView addSubview:self.numberPadDoneButton];
            [self.numberPadDoneButton addTarget:self action:@selector(numberPadDoneButton:) forControlEvents:UIControlEventTouchUpInside];
            break;
        }
    }
}

- (void)textFieldDidBeginEditing:(NSNotification *)note {
    [self updateKeyboardButtonFor:[note object]];
}

- (void)keyboardWillShow:(NSNotification *)note {
    [self updateKeyboardButtonFor:[self findFirstResponderTextField]];
}

- (void)keyboardDidShow:(NSNotification *)note {
    [self updateKeyboardButtonFor:[self findFirstResponderTextField]];
}

- (IBAction)numberPadDoneButton:(id)sender {
    UITextField *textField = [self findFirstResponderTextField];
    [textField resignFirstResponder];
}

- (void)dealloc {
    [numberPadDoneImageNormal release];
    [numberPadDoneImageHighlighted release];
    [numberPadDoneButton release];
    [super dealloc];
}

@end

наслаждайтесь.


Ниже приведен обзор ответа Люды со следующими изменениями:

  • вид аксессуара автоматически определяется по ширине рамки приложения

  • устаревшая константа UIBarButtonItemStyleBordered расторгнут

  • кнопка "готово" создается как UIBarButtonSystemItemDone

В настоящее время кнопка" готово " находится по центру в представлении аксессуаров. Вы можете расположить его слева или справа, удалив пространства на соответствующей стороне.

Я опустил кнопку "Отмена", потому что клавиатура по умолчанию тоже нет. Если вы хотите кнопку "Отмена", я предлагаю вам создать ее как UIBarButtonSystemItemCancel и убедитесь, что вы не отбрасываете исходное значение в текстовом поле. Поведение "отмена", реализованное в ответе Люды, которое перезаписывает значение пустой строкой, может быть не тем, что вы хотите.

- (void)viewDidLoad {
  [super viewDidLoad];
  float appWidth = CGRectGetWidth([UIScreen mainScreen].applicationFrame);
  UIToolbar *accessoryView = [[UIToolbar alloc]
                              initWithFrame:CGRectMake(0, 0, appWidth, 0.1 * appWidth)];
  UIBarButtonItem *space = [[UIBarButtonItem alloc]
                            initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
                            target:nil
                            action:nil];
  UIBarButtonItem *done = [[UIBarButtonItem alloc]
                           initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                           target:self
                           action:@selector(selectDoneButton)];
  accessoryView.items = @[space, done, space];
  self.valueField.inputAccessoryView = accessoryView;
}

- (void)selectDoneButton {
  [self.valueField resignFirstResponder];
}

для Больше информации о аксессуаре здания просмотры, см. документацию Apple на настраиваемые представления для ввода данных. Вы, вероятно, захотите ознакомиться со ссылочными страницами на UIToolbar и UIBarButtonItem как хорошо.


вот самый последний код. Просто включить #импорт " UIViewController+NumPadReturn.h " в вашем viewController.

здесь .h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIViewController (NumPadReturn)



@end

а .м

#import "UIViewController+NumPadReturn.h"


@implementation UIViewController (NumPadReturn)

-(void) viewDidLoad{
    // add observer for the respective notifications (depending on the os version)
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(keyboardDidShow:) 
                                                     name:UIKeyboardDidShowNotification 
                                                   object:nil];     
    } else {
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(keyboardWillShow:) 
                                                     name:UIKeyboardWillShowNotification 
                                                   object:nil];
    }

}


- (void)keyboardWillShow:(NSNotification *)note {
    // if clause is just an additional precaution, you could also dismiss it
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 3.2) {
        [self addButtonToKeyboard];
    }
}

- (void)keyboardDidShow:(NSNotification *)note {
    // if clause is just an additional precaution, you could also dismiss it
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
        [self addButtonToKeyboard];
    }
}

- (void)addButtonToKeyboard {
    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(0, 163, 106, 53);
    doneButton.adjustsImageWhenHighlighted = NO;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.0) {
        [doneButton setImage:[UIImage imageNamed:@"DoneUp3.png"] forState:UIControlStateNormal];
        [doneButton setImage:[UIImage imageNamed:@"DoneDown3.png"] forState:UIControlStateHighlighted];
    } else {        
        [doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal];
        [doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted];
    }
    [doneButton addTarget:self action:@selector(doneButton:) 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 found, add the button
        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
            if([[keyboard description] hasPrefix:@"<UIPeripheralHost"] == YES)
                [keyboard addSubview:doneButton];
        } else {
            if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
                [keyboard addSubview:doneButton];
        }
    }
}

- (void)doneButton:(id)sender {
    NSLog(@"doneButton");
    [self.view endEditing:TRUE];
}



@end

A Swift 3 решение с помощью расширения. Идеально, если у вас есть несколько числовых UITextField объекты в вашем приложении, как это дает гибкость, чтобы решить, для каждого UITextField, следует ли выполнять пользовательское действие, когда сделал или отмена постучал.

enter image description here

//
//  UITextField+DoneCancelToolbar.swift
//

import UIKit

extension UITextField {
    func addDoneCancelToolbar(onDone: (target: Any, action: Selector)? = nil, onCancel: (target: Any, action: Selector)? = nil) {     
        let onCancel = onCancel ?? (target: self, action: #selector(cancelButtonTapped))
        let onDone = onDone ?? (target: self, action: #selector(doneButtonTapped))

        let toolbar: UIToolbar = UIToolbar()
        toolbar.barStyle = .default
        toolbar.items = [
            UIBarButtonItem(title: "Cancel", style: .plain, target: onCancel.target, action: onCancel.action),
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil),
            UIBarButtonItem(title: "Done", style: .done, target: onDone.target, action: onDone.action)
        ]
        toolbar.sizeToFit()

        self.inputAccessoryView = toolbar
    }

    // Default actions:  
    func doneButtonTapped() { self.resignFirstResponder() }
    func cancelButtonTapped() { self.resignFirstResponder() }
}

пример использования действий по умолчанию:

//
// MyViewController.swift
//

@IBOutlet weak var myNumericTextField: UITextField! {
    didSet { myNumericTextField?.addDoneCancelToolbar() }
}

пример использования с помощью пользовательского сделал действие:

//
// MyViewController.swift
//

@IBOutlet weak var myNumericTextField: UITextField! {
    didSet { 
        myNumericTextField?.addDoneCancelToolbar(onDone: (target: self, action: #selector(doneButtonTappedForMyNumericTextField))) 
    }
}

func doneButtonTappedForMyNumericTextField() { 
    print("Done"); 
    myNumericTextField.resignFirstResponder() 
}

гораздо более простое решение

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesBegan:touches withEvent:event];

    [textViewInstance1 resignFirstResponder];
    [textViewInstance2 resignFirstResponder];
    [textField resignFirstResponder];
}

данное сообщение на форуме описывает, как настроить UIKeyboard для добавления пользовательского представления на клавиатуру.


нашел @user1258240 это быть довольно кратким, учитывая, что это не так просто, как задание returnKeyType собственность.

просто хотел внести свой собственный" повторно используемый " подход к этому:

func SetDoneToolbar(field:UITextField) {
    let doneToolbar:UIToolbar = UIToolbar()

    doneToolbar.items=[
        UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: self, action: nil),
        UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(ViewController.dismissKeyboard))
    ]

    doneToolbar.sizeToFit()
    field.inputAccessoryView = doneToolbar
}

override func viewDidLoad() {
    super.viewDidLoad()

    SetDoneToolbar(field: UITextField_1)
    SetDoneToolbar(field: UITextField_2)
    SetDoneToolbar(field: UITextField_3)
    SetDoneToolbar(field: UITextField_N)
}

SWIFT 3.0 другой вкус, используя части некоторых предыдущих ответов.

func addToolbarToNumberPad()
{
    let numberPadToolbar: UIToolbar = UIToolbar()

    numberPadToolbar.isTranslucent = true
    numberPadToolbar.items=[
        UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(self.cancelAction)),
        UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil),
        UIBarButtonItem(title: "Custom", style: .done, target: self, action: #selector(self.customAction)),
        UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.doneAction)),
    ]

    numberPadToolbar.sizeToFit()

    textField.inputAccessoryView = numberPadToolbar
}

func cancelAction()
{
    textField.resignFirstResponder()
}

func customAction()
{
    textField.resignFirstResponder()
}

func doneAction()
{
    textField.resignFirstResponder()
}

override func viewDidLoad()
{
    super.viewDidLoad()

    self.addToolbarToNumberPad()
}

я описываю одно решение для iOS 4.2+ здесь но кнопка уволить исчезает после появления клавиатуры. Это не ужасно, но и не идеально.

решение, описанное в вопросе, связанном выше, включает в себя более элегантную иллюзию, чтобы отклонить кнопку, где я исчезаю и вертикально перемещаю кнопку, чтобы обеспечить внешний вид, что клавиатура и кнопка отклоняются вместе.


на простой путь:

создать пользовательская прозрачная кнопка и поместите его в левый нижний угол, который будет иметь то же самое CGSize как пустое место в UIKeyboardTypeNumberPad. Переключить (Показать / Скрыть) эту кнопку на textField becomeFirstResponder, по нажатию кнопки соответственно.


вот самое простое решение, с которым я столкнулся. Я узнал об этом из книги по разработке iOS 5.

предполагая, что числовое поле называется numberField.

  1. на ViewController добавьте следующий метод:

    -(IBAction)closeKeyboard:(id)sender;
    
  2. на ViewController.m добавьте следующий код:

    -(IBAction)closeKeyboard:(id)sender
    {
    
         [numberField resignFirstResponder];
    
    }
    
  3. вернуться в .

  4. открыть Utilities Пан.
  5. открыть Identity inspector под Utilities Пан.
  6. нажмите на кнопку View (в файле nib) раз. Убедитесь, что вы не нажали ни на один из элементов в представлении. Для уточнения, вы должны увидеть UIView под Class на Identity inspector.
  7. измените класс с UIView на UIControl.
  8. открыть Connection Inspector.
  9. нажмите и перетащите Touch Down и перетащите стрелку на . (К ВАШЕМУ СВЕДЕНИЮ... Значок владельца файла отображается слева от View и появляется как пустота куб с желтой рамкой.)
  10. выберите метод: closeKeyboard.
  11. запустить программу.

теперь, когда вы щелкните в любом месте на фоне View, вы должны иметь возможность отклонить клавиатуру.

надеюсь, это поможет вам решить вашу проблему. :-)


Я изменил решение Брайана, чтобы быть немного более надежным, так что он будет играть хорошо с другими типами клавиатур, которые могут появиться в том же виде. Это описано здесь:

создать кнопку Готово на клавиатуре iOS uikeyboard

Я бы попытался объяснить это здесь, но большая часть этого кода, чтобы посмотреть, что было бы нелегко здесь


Если вы заранее знаете количество введенных номеров (например, 4-значный PIN-код), вы можете автоматически уволить после 4 нажатий клавиш, согласно моему ответу на этот аналогичный вопрос:

увольнение цифровой клавиатуре

в этом случае нет необходимости в дополнительной кнопке done.


мы также можем сделать "пользователь коснулся где-то еще" решение еще проще, если мы просто скажем, что наш вид контроллера для завершения редактирования:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
 { 
      [super touchesBegan:touches withEvent:event];

      [self.view endEditing:YES]; //YES ignores any textfield refusal to resign
 }

... предполагая, что" прикосновение в другом месте отклоняет клавиатуру " является желаемым поведением для любых других редактируемых полей в представлении.


Если у вас есть несколько числовых полей, я предлагаю подклассы UITextField для создания NumericTextField, который всегда отображает числовую клавиатуру с кнопкой Готово. Затем просто свяжите числовые поля с этим классом в Построителе интерфейса, и вам не понадобится дополнительный код ни в одном из контроллеров представления. Ниже приведен класс Swift 3.0, который я использую в Xcode 8.0.

class NumericTextField: UITextField {
   let numericKbdToolbar = UIToolbar()

    // MARK: Initilization
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.initialize()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.initialize()
    }

    // Sets up the input accessory view with a Done button that closes the keyboard
    func initialize()
    {
        self.keyboardType = UIKeyboardType.numberPad

        numericKbdToolbar.barStyle = UIBarStyle.default
        let space = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        let callback = #selector(NumericTextField.finishedEditing)
        let donebutton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: callback)
        numericKbdToolbar.setItems([space, donebutton], animated: false)
        numericKbdToolbar.sizeToFit()
        self.inputAccessoryView = numericKbdToolbar
    }

    // MARK: On Finished Editing Function
    func finishedEditing()
    {
        self.resignFirstResponder()
    }
}

для Swift 2.2 я использую это

func addDoneButtonOnKeyboard() {
    let doneToolbar: UIToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.bounds.size.width, 50))

    let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
    let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: #selector(DetailViewController.finishDecimalKeypad))

    var items: [UIBarButtonItem]? = [UIBarButtonItem]()
    items?.append(flexSpace)
    items?.append(done)

    doneToolbar.items = items
    doneToolbar.sizeToFit()
    self.productPrice.inputAccessoryView=doneToolbar
}

func finishDecimalKeypad() {
    self.productPrice?.resignFirstResponder()
}

все эти реализации о поиске вида клавиатуры и добавлении кнопки "Готово" в 3-й строке (вот почему кнопка.y = 163 B / C высота клавиатуры 216) являются хрупкими, потому что iOS продолжает изменять иерархию представления. Например, ни один из вышеперечисленных кодов не работает для iOS9.

Я думаю, что более безопасно просто найти самый верхний вид, с помощью [[[UIApplication sharedApplication] windows] lastObject], и просто добавьте кнопку в левом нижнем углу, doneButton.frame = CGRectMake(0, SCREEN_HEIGHT-53, 106, 53);// портретный режим


Swift 2.2 / я использовал ответ Dx_. Тем не менее, я хотел эту функциональность на всех клавиатурах. Поэтому в моем базовом классе я поставил код:

func addDoneButtonForTextFields(views: [UIView]) {
    for view in views {
        if let textField = view as? UITextField {
            let doneToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.bounds.size.width, 50))

            let flexSpace = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
            let done = UIBarButtonItem(title: "Done", style: .Done, target: self, action: #selector(dismissKeyboard))

            var items = [UIBarButtonItem]()
            items.append(flexSpace)
            items.append(done)

            doneToolbar.items = items
            doneToolbar.sizeToFit()

            textField.inputAccessoryView = doneToolbar
        } else {
            addDoneButtonForTextFields(view.subviews)
        }
    }
}

func dismissKeyboard() {
    dismissKeyboardForTextFields(self.view.subviews)
}

func dismissKeyboardForTextFields(views: [UIView]) {
    for view in views {
        if let textField = view as? UITextField {
            textField.resignFirstResponder()
        } else {
            dismissKeyboardForTextFields(view.subviews)
        }
    }
}

затем просто вызовите addDoneButtonForTextFields на self.вид.subviews в viewDidLoad (или willDisplayCell, если используется табличное представление), чтобы добавить кнопку Готово на все клавиатуры.