Как получить нажатия клавиш с пользовательской клавиатуры в приложении iOS?

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

Apple предоставляет механизм inputView, который позволяет легко связать пользовательскую клавиатуру с UITextField или UITextView, но они не предоставляют функции для отправки сгенерированных нажатий клавиш обратно в связанный объект. Основываясь на типичном делегировании для этих объектов, мы ожидаем три функции: одну для обычных символов, одну для возврата и одну для ввода. Тем не менее, похоже, никто не дает четкого определения этих функций или того, как их использовать.

Как мне создать пользовательскую клавиатуру для моего приложения iOS и получать от нее нажатия клавиш?


person Greg Young    schedule 03.11.2012    source источник


Ответы (4)


Подход Грега должен работать, но у меня есть подход, который не требует, чтобы клавиатура сообщала о текстовом поле или текстовом представлении. Фактически, вы можете создать один экземпляр клавиатуры и назначить его нескольким текстовым полям и/или текстовым представлениям. Клавиатура знает, какой из них отвечает первым.

Вот мой подход. Я не буду показывать какой-либо код для создания раскладки клавиатуры. Это легкая часть. Этот код показывает всю сантехнику.

Изменить: это было обновлено, чтобы правильно обрабатывать UITextFieldDelegate textField:shouldChangeCharactersInRange:replacementString: и UITextViewDelegate textView:shouldChangeTextInRange:replacementText:.

Заголовочный файл:

@interface SomeKeyboard : UIView <UIInputViewAudioFeedback>

@end

Файл реализации:

@implmentation SomeKeyboard {
    id<UITextInput> _input;
    BOOL _tfShouldChange;
    BOOL _tvShouldChange;
}

- (id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkInput:) name:UITextFieldTextDidBeginEditingNotification object:nil];
    }

    return self;
}

// This is used to obtain the current text field/view that is now the first responder
- (void)checkInput:(NSNotification *)notification {
    UITextField *field = notification.object;

    if (field.inputView && self == field.inputView) {
        _input = field;

        _tvShouldChange = NO;
        _tfShouldChange = NO;
        if ([_input isKindOfClass:[UITextField class]]) {
            id<UITextFieldDelegate> del = [(UITextField *)_input delegate];
            if ([del respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
                _tfShouldChange = YES;
            }
        } else if ([_input isKindOfClass:[UITextView class]]) {
            id<UITextViewDelegate> del = [(UITextView *)_input delegate];
            if ([del respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) {
                _tvShouldChange = YES;
            }
        }
    }
}

// Call this for each button press
- (void)click {
    [[UIDevice currentDevice] playInputClick];
}

// Call this when a button on the keyboard is tapped (other than return or backspace)
- (void)keyTapped:(UIButton *)button {
    NSString *text = ???; // determine text for the button that was tapped

    if ([_input respondsToSelector:@selector(shouldChangeTextInRange:replacementText:)]) {
        if ([_input shouldChangeTextInRange:[_input selectedTextRange] replacementText:text]) {
            [_input insertText:text];
        }
    } else if (_tfShouldChange) {
        NSRange range = [(UITextField *)_input selectedRange];
        if ([[(UITextField *)_input delegate] textField:(UITextField *)_input shouldChangeCharactersInRange:range replacementString:text]) {
            [_input insertText:text];
        }
    } else if (_tvShouldChange) {
        NSRange range = [(UITextView *)_input selectedRange];
        if ([[(UITextView *)_input delegate] textView:(UITextView *)_input shouldChangeTextInRange:range replacementText:text]) {
            [_input insertText:text];
        }
    } else {
        [_input insertText:text];
    }
}

// Used for a UITextField to handle the return key button
- (void)returnTapped:(UIButton *)button {
    if ([_input isKindOfClass:[UITextField class]]) {
        id<UITextFieldDelegate> del = [(UITextField *)_input delegate];
        if ([del respondsToSelector:@selector(textFieldShouldReturn:)]) {
            [del textFieldShouldReturn:(UITextField *)_input];
        }
    } else if ([_input isKindOfClass:[UITextView class]]) {
        [_input insertText:@"\n"];
    }
}

// Call this to dismiss the keyboard
- (void)dismissTapped:(UIButton *)button {
    [(UIResponder *)_input resignFirstResponder];
}

// Call this for a delete/backspace key
- (void)backspaceTapped:(UIButton *)button {
    if ([_input respondsToSelector:@selector(shouldChangeTextInRange:replacementText:)]) {
        UITextRange *range = [_input selectedTextRange];
        if ([range.start isEqual:range.end]) {
            UITextPosition *newStart = [_input positionFromPosition:range.start inDirection:UITextLayoutDirectionLeft offset:1];
            range = [_input textRangeFromPosition:newStart toPosition:range.end];
        }
        if ([_input shouldChangeTextInRange:range replacementText:@""]) {
            [_input deleteBackward];
        }
    } else if (_tfShouldChange) {
        NSRange range = [(UITextField *)_input selectedRange];
        if (range.length == 0) {
            if (range.location > 0) {
                range.location--;
                range.length = 1;
            }
        }
        if ([[(UITextField *)_input delegate] textField:(UITextField *)_input shouldChangeCharactersInRange:range replacementString:@""]) {
            [_input deleteBackward];
        }
    } else if (_tvShouldChange) {
        NSRange range = [(UITextView *)_input selectedRange];
        if (range.length == 0) {
            if (range.location > 0) {
                range.location--;
                range.length = 1;
            }
        }
        if ([[(UITextView *)_input delegate] textView:(UITextView *)_input shouldChangeTextInRange:range replacementText:@""]) {
            [_input deleteBackward];
        }
    } else {
        [_input deleteBackward];
    }

    [self updateShift];
}

@end

Для этого класса требуется метод категории для UITextField:

@interface UITextField (CustomKeyboard)

- (NSRange)selectedRange;

@end

@implementation UITextField (CustomKeyboard)

- (NSRange)selectedRange {
    UITextRange *tr = [self selectedTextRange];

    NSInteger spos = [self offsetFromPosition:self.beginningOfDocument toPosition:tr.start];
    NSInteger epos = [self offsetFromPosition:self.beginningOfDocument toPosition:tr.end];

    return NSMakeRange(spos, epos - spos);
}

@end
person rmaddy    schedule 03.11.2012
comment
Я знаю, что это старый ответ, но я пробую ваш ответ и заметил, что он дает мне ошибку [self updateShift]; Это метод, который должен быть включен в вашу выборку, или он взят откуда-то еще? - person Connor; 28.04.2014
comment
Вы можете отказаться от вызова этого метода. В моей настоящей пользовательской клавиатуре у меня есть клавиша Shift, которую я обновляю так же, как клавишу Shift на стандартной клавиатуре по умолчанию. Это выходит за рамки этого ответа. - person rmaddy; 28.04.2014
comment
Спасибо за вашу помощь. Должен ли я делать что-либо, кроме установки моей клавиатуры в качестве inputView текстового поля? Прямо сейчас я все настроил и проверил, что он переходит в метод keyTapped при нажатии кнопки, но текстовое поле не меняется - person Connor; 28.04.2014
comment
Убедитесь, что метод checkInput вызывается, когда текстовое поле получает фокус. - person rmaddy; 28.04.2014
comment
Взгляните на мой пример, чтобы увидеть, как это сделать без необходимости создания подкласса UITextField. - person lnafziger; 11.06.2015
comment
@lnafziger Мой подход также не требует подкласса UITextField. Я добавил метод категории только для того, чтобы упростить получение выбранного диапазона. И зачем вспоминать об этом спустя 2,5 года? - person rmaddy; 11.06.2015
comment
Ой, извините, категория. И кто-то еще прокомментировал, что привлекло мое внимание к этому вопросу, и я решил, что укажу вам другой способ сделать это на всякий случай, если вам интересно. :) - person lnafziger; 11.06.2015

Я создал полный рабочий пример клавиатуры для iPad, доступный на Github здесь:

https://github.com/lnafziger/Numberpad

Numberpad — это настраиваемая цифровая клавиатура для iPad, которая работает как с UITextField, так и с UITextView, не требуя никаких изменений, кроме добавления экземпляра класса Numberpad в качестве inputView текстового поля/представления.

Функции:

  • На него распространяется лицензия Массачусетского технологического института, поэтому его можно свободно копировать и использовать в соответствии с его условиями.
  • Он работает с UITextFields и UITextViews.
  • Он не требует установки делегата.
  • Он автоматически отслеживает, какое представление отвечает первым (так что вам не нужно)
  • Вам не нужно устанавливать размер клавиатуры или следить за ним.
  • Существует общий экземпляр, который вы можете использовать для любого количества входных представлений, не используя дополнительную память для каждого из них.

Использование так же просто, как включить Numberpad.h, а затем:

theTextField.inputView  = [Numberpad defaultNumberpad];

Все остальное позаботится автоматически!

Либо возьмите два файла классов и xib из Github (ссылка выше), либо создайте кнопки (в коде или в раскадровке/xib) с их действиями, установленными для соответствующих методов в классе (numberpadNumberPressed, numberpadDeletePressed, numberpadClearPressed или numberpadDonePressed ).

Следующий код устарел. См. проект Github для получения последней версии кода.

Цифровая клавиатура.h:

#import <UIKit/UIKit.h>

@interface Numberpad : UIViewController

// The one and only Numberpad instance you should ever need:
+ (Numberpad *)defaultNumberpad;

@end

Цифровой блок.м:

#import "Numberpad.h"

#pragma mark - Private methods

@interface Numberpad ()

@property (nonatomic, weak) id<UITextInput> targetTextInput;

@end

#pragma mark - Numberpad Implementation

@implementation Numberpad

@synthesize targetTextInput;

#pragma mark - Shared Numberpad method

+ (Numberpad *)defaultNumberpad {
    static Numberpad *defaultNumberpad = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        defaultNumberpad = [[Numberpad alloc] init];
    });

    return defaultNumberpad;
}

#pragma mark - view lifecycle

- (void)viewDidLoad {
    [super viewDidLoad];

    // Keep track of the textView/Field that we are editing
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(editingDidBegin:)
                                                 name:UITextFieldTextDidBeginEditingNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(editingDidBegin:)
                                                 name:UITextViewTextDidBeginEditingNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(editingDidEnd:)
                                                 name:UITextFieldTextDidEndEditingNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(editingDidEnd:)
                                                 name:UITextViewTextDidEndEditingNotification
                                               object:nil];
}

- (void)viewDidUnload {
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UITextFieldTextDidBeginEditingNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UITextViewTextDidBeginEditingNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UITextFieldTextDidEndEditingNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UITextViewTextDidEndEditingNotification
                                                  object:nil];
    self.targetTextInput = nil;

    [super viewDidUnload];
}

#pragma mark - editingDidBegin/End

// Editing just began, store a reference to the object that just became the firstResponder
- (void)editingDidBegin:(NSNotification *)notification {
    if (![notification.object conformsToProtocol:@protocol(UITextInput)]) {
        self.targetTextInput = nil;
        return;
    }

    self.targetTextInput = notification.object;
}

// Editing just ended.
- (void)editingDidEnd:(NSNotification *)notification {
    self.targetTextInput = nil;
}

#pragma mark - Keypad IBActions

// A number (0-9) was just pressed on the number pad
// Note that this would work just as well with letters or any other character and is not limited to numbers.
- (IBAction)numberpadNumberPressed:(UIButton *)sender {
    if (!self.targetTextInput) {
        return;
    }

    NSString *numberPressed  = sender.titleLabel.text;
    if ([numberPressed length] == 0) {
        return;
    }

    UITextRange *selectedTextRange = self.targetTextInput.selectedTextRange;
    if (!selectedTextRange) {
        return;
    }

    [self textInput:self.targetTextInput replaceTextAtTextRange:selectedTextRange withString:numberPressed];
}

// The delete button was just pressed on the number pad
- (IBAction)numberpadDeletePressed:(UIButton *)sender {
    if (!self.targetTextInput) {
        return;
    }

    UITextRange *selectedTextRange = self.targetTextInput.selectedTextRange;
    if (!selectedTextRange) {
        return;
    }

    // Calculate the selected text to delete
    UITextPosition  *startPosition  = [self.targetTextInput positionFromPosition:selectedTextRange.start offset:-1];
    if (!startPosition) {
        return;
    }
    UITextPosition  *endPosition    = selectedTextRange.end;
    if (!endPosition) {
        return;
    }
    UITextRange     *rangeToDelete  = [self.targetTextInput textRangeFromPosition:startPosition
                                                                       toPosition:endPosition];

    [self textInput:self.targetTextInput replaceTextAtTextRange:rangeToDelete withString:@""];
}

// The clear button was just pressed on the number pad
- (IBAction)numberpadClearPressed:(UIButton *)sender {
    if (!self.targetTextInput) {
        return;
    }

    UITextRange *allTextRange = [self.targetTextInput textRangeFromPosition:self.targetTextInput.beginningOfDocument
                                                                 toPosition:self.targetTextInput.endOfDocument];

    [self textInput:self.targetTextInput replaceTextAtTextRange:allTextRange withString:@""];
}

// The done button was just pressed on the number pad
- (IBAction)numberpadDonePressed:(UIButton *)sender {
    if (!self.targetTextInput) {
        return;
    }

    // Call the delegate methods and resign the first responder if appropriate
    if ([self.targetTextInput isKindOfClass:[UITextView class]]) {
        UITextView *textView = (UITextView *)self.targetTextInput;
        if ([textView.delegate respondsToSelector:@selector(textViewShouldEndEditing:)]) {
            if ([textView.delegate textViewShouldEndEditing:textView]) {
                [textView resignFirstResponder];
            }
        }
    } else if ([self.targetTextInput isKindOfClass:[UITextField class]]) {
        UITextField *textField = (UITextField *)self.targetTextInput;
        if ([textField.delegate respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
            if ([textField.delegate textFieldShouldEndEditing:textField]) {
                [textField resignFirstResponder];
            }
        }
    }
}

#pragma mark - text replacement routines

// Check delegate methods to see if we should change the characters in range
- (BOOL)textInput:(id <UITextInput>)textInput shouldChangeCharactersInRange:(NSRange)range withString:(NSString *)string
{
    if (!textInput) {
        return NO;
    }

    if ([textInput isKindOfClass:[UITextField class]]) {
        UITextField *textField = (UITextField *)textInput;
        if ([textField.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            if (![textField.delegate textField:textField
                 shouldChangeCharactersInRange:range
                             replacementString:string]) {
                return NO;
            }
        }
    } else if ([textInput isKindOfClass:[UITextView class]]) {
        UITextView *textView = (UITextView *)textInput;
        if ([textView.delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) {
            if (![textView.delegate textView:textView
                     shouldChangeTextInRange:range
                             replacementText:string]) {
                return NO;
            }
        }
    }
    return YES;
}

// Replace the text of the textInput in textRange with string if the delegate approves
- (void)textInput:(id <UITextInput>)textInput replaceTextAtTextRange:(UITextRange *)textRange withString:(NSString *)string {
    if (!textInput) {
        return;
    }
    if (!textRange) {
        return;
    }

    // Calculate the NSRange for the textInput text in the UITextRange textRange:
    int startPos                    = [textInput offsetFromPosition:textInput.beginningOfDocument
                                                         toPosition:textRange.start];
    int length                      = [textInput offsetFromPosition:textRange.start
                                                         toPosition:textRange.end];
    NSRange selectedRange           = NSMakeRange(startPos, length);

    if ([self textInput:textInput shouldChangeCharactersInRange:selectedRange withString:string]) {
        // Make the replacement:
        [textInput replaceRange:textRange withText:string];
    }
}

@end
person lnafziger    schedule 12.11.2012

Вот моя пользовательская клавиатура, которая, как мне кажется, решает эти проблемы настолько полно, насколько это позволит Apple:

//  PVKeyboard.h

#import <UIKit/UIKit.h>
@interface PVKeyboard : UIView
@property (nonatomic,assign) UITextField *textField;
@end

//  PVKeyboard.m

#import "PVKeyboard.h"

@interface PVKeyboard () {
    UITextField *_textField;
}
@property (nonatomic,assign) id<UITextInput> delegate;
@end

@implementation PVKeyboard

- (id<UITextInput>) delegate {
    return _textField;
}

- (UITextField *)textField {
    return _textField;
}

- (void)setTextField:(UITextField *)tf {
    _textField = tf;
    _textField.inputView = self;
}

- (IBAction)dataPress:(UIButton *)btn {
    [self.delegate insertText:btn.titleLabel.text];
}

- (IBAction)backPress {
    if ([self.delegate conformsToProtocol:@protocol(UITextInput)]) {
        [self.delegate deleteBackward];
    } else {
        int nLen = [_textField.text length];
        if (nLen)
            _textField.text = [_textField.text substringToIndex:nLen-1];
    }
}

- (IBAction)enterPress {
    [_textField.delegate textFieldShouldReturn:_textField];
}

- (UIView *)loadWithNIB {
   NSArray *aNib = [[NSBundle mainBundle]loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
   UIView *view = [aNib objectAtIndex:0];
   [self addSubview:view];
   return view;
}

- (id)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self)
        [self loadWithNIB];
   return self;
}
@end

В XCode 4.3 и более поздних версиях вам необходимо создать объектный класс (для файлов .h и .m) на основе UIView и файла представления пользовательского интерфейса (для файла .xib). Убедитесь, что все три файла имеют одинаковое имя. Используя Identity Inspector, убедитесь, что пользовательский класс владельца файла XIB соответствует имени нового объекта. Используя Инспектор атрибутов, установите размер формы на Свободную форму и установите для строки состояния значение «Нет». С помощью Инспектора размеров задайте размер формы, который должен соответствовать ширине стандартной клавиатуры (320 для портретной ориентации iPhone и 480 для альбомной ориентации iPhone), но вы можете выбрать любую высоту по своему усмотрению.

Форма готова к использованию. Добавьте кнопки и подключите их к dataPress, backPress и enterPress по мере необходимости. Функции initWithFrame: и loadWithNIB сделают все возможное, чтобы вы могли использовать клавиатуру, разработанную в Interface Builder.

Чтобы использовать эту клавиатуру с UITextField myTextField, просто добавьте следующий код в ваш viewDidLoad:

self.keyboard = [[PVKeyboard alloc]initWithFrame:CGRectMake(0,488,320,60)];
self.keyboard.textField = self.myTextField;

Из-за некоторых ограничений эту клавиатуру нельзя использовать повторно, поэтому вам потребуется по одной на каждое поле. Я почти могу сделать его многоразовым, но я просто не чувствую себя таким умным. Клавиатура также ограничена UITextFields, но это в основном из-за ограничений в реализации функций клавиши ввода, которые я объясню ниже.

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

Я реализовал единственное свойство этой клавиатуры, textField, используя дискретный дискретный установщик (setTextField), потому что:

  1. нам нужен объект UITextField для обработки проблемы ввода
  2. нам нужен UITextField, потому что он соответствует протоколу UITextInput, который соответствует UIKeyInput, который выполняет большую часть нашей тяжелой работы.
  3. это было удобное место для установки поля inputView UITextInput для использования этой клавиатуры.

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

Функция dataPress вставляет текстовый ввод в редактируемое поле с помощью метода insertText UIKeyInput. Кажется, это работает во всех версиях, начиная с iOS 4. Для моей клавиатуры я просто использую метку каждой кнопки, что вполне нормально. Используйте любые NSStrings, которые вам понравятся.

Функция dataBack выполняет возврат и немного сложнее. Когда работает UIKeyInput deleteBackward, он работает чудесно. И хотя в документации говорится, что он работает с iOS 3.2, похоже, он работает только с iOS 5.0, когда UITextField (и UITextView) соответствует протоколу UITextInput. Так что до этого вы предоставлены сами себе. Поскольку поддержка iOS 4 беспокоит многих, я реализовал хромой backspace, который работает напрямую с UITextField. Если бы не это требование, я мог бы заставить эту клавиатуру работать с UITextView. И этот возврат не такой общий, только удаление последнего символа, в то время как deleteBackward будет работать правильно, даже если пользователь перемещает курсор.

Функция enterPress реализует клавишу ввода, но это полная ерунда, потому что Apple, похоже, не предоставляет метод для вызова клавиши ввода. Таким образом, enterPress просто вызывает функцию делегата UITextField textFieldShouldReturn:, которую реализует большинство программистов. Обратите внимание, что делегатом здесь является UITextFieldDelegate для UITextField, а НЕ свойство делегата для самой клавиатуры.

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

Вот и все. Потребовалось 24 часа чтения и копания, чтобы сделать эту работу. Я надеюсь, что это поможет кому-то.

person Greg Young    schedule 03.11.2012
comment
Пока я отвечаю на ваш комментарий, у меня есть один для вас. :) В вашем методе enterPress есть один небольшой недостаток. Предполагается, что UITextFieldDelegate реализует метод textFieldShouldReturn:. Это может быть небезопасным предположением. - person rmaddy; 03.11.2012
comment
Вы сами отвечаете на свой вопрос? - person sunkehappy; 03.11.2012
comment
@rmaddy Да, я сделал это предположение (я говорю это в тексте, потому что мы все в значительной степени обязаны уйти в отставку в качестве первого ответчика и, возможно, выбрать следующее поле, чтобы стать первым ответчиком). Но вы правы, было бы безопаснее/лучше проверить, существует ли метод перед вызовом. - person Greg Young; 03.11.2012
comment
@sunkehappy Я знаю ... Я изначально не публиковал это таким образом. Но когда я опубликовал один пост с общим ответом на вопрос, который я видел несколько раз здесь и на форумах разработчиков Apple, меня попросили задать его как вопрос, а затем ответить на него. Мне тоже это кажется странным, но когда в Риме... - person Greg Young; 03.11.2012
comment
Да, Грег, это мне очень помогло, большое спасибо, что нашли время поделиться этим! - person Fabrizio Prosperi; 06.11.2012
comment
В лучшем мире клавиатура не должна знать (сохранять, копировать, хранить информацию) о входном представлении. ПО МОЕМУ МНЕНИЮ. Я бы предпочел ответ rmaddy. - person kas-kad; 27.05.2014
comment
Взгляните на мой пример, который устраняет все ограничения, которые вы упоминаете в своем примере. т.е. его можно использовать повторно, он не требует ручного отслеживания того, какой ввод редактируется, он работает с UITextView и т. д. - person lnafziger; 11.06.2015

(В основном это взято с http://blog.carbonfive.com/2012/03/12/customizing-the-ios-keyboard/)

В iOS клавиатура для представления управляется UIResponder частью цепочки наследования представлений. Когда любой UIResponder, которому нужна клавиатура, становится первым ответчиком (записывается на пленку или иным образом активируется), UIResponder ищет в своем свойстве inputView представление, которое будет отображаться как клавиатура. Итак, чтобы создать пользовательскую клавиатуру и реагировать на события на ней, вам нужно создать представление с буквенными кнопками, связать контроллер представления с этим представлением и с кнопками для обработки нажатий, и вы должны установить это представление как inputView какого-то текстового поля.

Взгляните на ссылку для получения дополнительной информации.

person Linuxios    schedule 03.11.2012