2012-11-03 10 views
14

Potrzebuję zbudować niestandardową klawiaturę dla mojej aplikacji na iPhone'a. Previous questions and answers na ten temat koncentruje się na elementach wizualnych niestandardowej klawiatury, ale staram się zrozumieć, jak odzyskać naciśnięcia klawiszy z tej klawiatury.Jak mogę pobrać klawisze z niestandardowej klawiatury w aplikacji na iOS?

Apple udostępnia mechanizm inputView, który ułatwia powiązanie niestandardowej klawiatury z UITextField lub UITextView, ale nie zapewnia funkcji wysyłania wygenerowanych naciśnięć klawiszy do powiązanego obiektu. Opierając się na typowej delegacji dla tych obiektów, oczekiwalibyśmy trzech funkcji: jednej z normalnych znaków, jednej dla backspace i jednej dla enter. Jednak nikt nie wydaje się jasno określać tych funkcji i jak z nich korzystać.

W jaki sposób mogę utworzyć niestandardową klawiaturę dla mojej aplikacji na iOS i pobrać z niej naciśnięcia klawiszy?

Odpowiedz

12

Oto mój zwyczaj klawiatura, która wierzę adresy je jako zupełnie jak Apple pozwoli:

// 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 

w Xcode 4.3 i później, trzeba stworzyć obiektywną-klasa (dla plików .h & .M) na podstawie UIView i pliku widoku interfejsu użytkownika (dla pliku .xib). Upewnij się, że wszystkie trzy pliki mają tę samą nazwę. Używając Inspektora tożsamości, upewnij się, że ustawiono klasę niestandardową właściciela pliku XIB, aby pasowała do nazwy nowego obiektu. Korzystając z Inspektora atrybutów, ustaw rozmiar formularza na Freeform i ustaw opcję Pasek stanu na none. Korzystając z Inspektora rozmiarów, ustaw rozmiar formularza, który powinien odpowiadać szerokości standardowej klawiatury (320 dla portretu iPhone'a i 480 dla krajobrazu iPhone'a), ale możesz wybrać dowolną wysokość.

Formularz jest gotowy do użycia. Dodaj przyciski i podłącz je odpowiednio do danych dataPress, backPress i enterPress. Funkcje initWithFrame: i loadWithNIB wykonają całą magię, aby umożliwić korzystanie z klawiatury zaprojektowanej w Interface Builder.

Aby skorzystać z tej klawiatury z UITextField myTextField, wystarczy dodać następujący kod do viewDidLoad:

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

powodu pewnych ograniczeń, to klawiatura nie jest wielokrotnego użytku, więc trzeba po jednym w każdym polu. Mogę sprawić, że będzie to wielokrotnego użytku, ale po prostu nie czuję się tak sprytnie. Klawiatura jest również ograniczona do UITextFields, ale wynika to głównie z ograniczeń implementacji funkcji klawisza Enter, które wyjaśnię poniżej.

Oto magia, która powinna pozwalają zaprojektować lepszą klawiaturę niż te ramy rozrusznika ...

I zostały wdrożone jedyną własność tej klawiatury textField, stosując dyskretny dyskretny setter (setTextField), ponieważ :

  1. musimy obiekt UITextField do obsługi wejść problemu
  2. musimy UITextField ponieważ jest on zgodny z protokołem UITextInput zgodnego UIKeyInput, który robi dużo naszego podnoszenia ciężkich
  3. było to wygodne miejsce do ustawienia pola inputView UITextInput, aby użyć tej klawiatury.

Zauważysz drugą własność prywatną o nazwie delegat, która zasadniczo powoduje typowanie wskaźnika UITextField do wskaźnika UITextInput. Prawdopodobnie mógłbym obsłużyć tę obsadę w linii, ale wyczułem, że może to być przydatne jako funkcja przyszłej ekspansji, być może włączając obsługę UITextView.

Funkcja danePress wprowadza tekst do edytowanego pola przy użyciu metody insertText dla UIKeyInput. To wydaje się działać we wszystkich wersjach z powrotem do iOS 4. Dla mojej klawiatury, po prostu używam etykiety każdego przycisku, co jest całkiem normalne. Użyj dowolnego NSStringsa, który ci się podoba.

Funkcja functionBack wykonuje backspace i jest nieco bardziej skomplikowana. Kiedy UIKeyInput deleteBackward działa, działa cudownie. I chociaż dokumentacja mówi, że działa z systemem iOS 3.2, wydaje się, że działa tylko z systemem iOS 5.0, czyli wtedy, gdy UITextField (i UITextView) są zgodne z protokołem UITextInput. Więc przedtem jesteś sam. Ponieważ obsługa iOS 4 jest problemem dla wielu osób, zaimplementowałem lame backspace, który działa bezpośrednio na UITextField. Gdyby nie to wymaganie, mogłem sprawić, by klawiatura działała z UITextView. A ten backspace nie jest tak ogólny, usuwając tylko ostatni znak, podczas gdy deleteBackward będzie działał poprawnie, nawet jeśli użytkownik przesunie kursor.

Funkcja enterPress implementuje klawisz Enter, ale jest kompletnym kluderem, ponieważ Apple wydaje się nie podawać metody wywoływania klawisza Enter. Zatem enterPress po prostu wywołuje funkcję delegującą UITextField textFieldShouldReturn :, którą programuje większość programistów. Należy pamiętać, że delegatem jest tutaj UITextFieldDelegate dla UITextField, a NIE właściwość delegata dla samej klawiatury.

Rozwiązanie to obejmie normalne przetwarzanie klawiatury, co nie ma większego znaczenia w przypadku UITextField, ale czyni tę technikę bezużyteczną z UITextView, ponieważ istnieje teraz sposób wstawiania łamania linii w edytowanym tekście.

To wszystko. Aby to zadziałało, potrzeba było 24 godzin czytania i brukowania. Mam nadzieję, że to pomoże komuś.

+0

Chociaż ja odpowiadając na komentarz, mam jedną dla ciebie. :) Twoja metoda 'enterPress' ma jedną niewielką wadę. Zakłada, że ​​'UITextFieldDelegate' implementuje metodę' textFieldShouldReturn: '. To nie może być bezpieczne założenie. – rmaddy

+0

Odpowiadasz na własne pytanie? – sunkehappy

+0

@rmaddy Tak, zrobiłem to założenie (mówię tak samo w tekście, ponieważ wszyscy jesteśmy prawie zobowiązani do złożenia rezygnacji jako Pierwszy Odpowiadający i być może wybieramy następne pole, aby stać się Pierwszym Odpowiadającym). Ale masz rację, byłoby bezpieczniej/lepiej sprawdzić, aby upewnić się, że metoda istnieje przed wywołaniem. –

0

(Jest to głównie zaczerpnięte z http://blog.carbonfive.com/2012/03/12/customizing-the-ios-keyboard/)

w iOS, klawiatura dla widoku jest zarządzany przez UIResponder części łańcucha widok spadkowego. Gdy dowolny użytkownik UIRespaurer, który potrzebuje klawiatury, staje się pierwszym responderem (jest nagrywany lub aktywowany w inny sposób), UIResponder sprawdza w swojej właściwości inputView, aby widok był wyświetlany jako klawiatura. Aby utworzyć niestandardową klawiaturę i zareagować na zdarzenie na niej, należy utworzyć widok z przyciskami liter, powiązać kontroler widoku z tym widokiem oraz przyciskami do obsługi naciśnięć i ustawić ten widok jako inputView z niektórych pól tekstowych.

Zobacz link, aby uzyskać więcej informacji.

18

Podejście Grega powinno zadziałać, ale mam podejście, które nie wymaga od klawiatury mówienia o polu tekstowym lub widoku tekstu. W rzeczywistości można utworzyć pojedyncze wystąpienie klawiatury i przypisać ją do wielu pól tekstowych i/lub widoków tekstowych. Klawiatura obsługuje rozpoznanie, która z nich jest pierwszą odpowiedzią.

Oto moje podejście. Nie zamierzam pokazywać żadnego kodu do tworzenia układu klawiatury. To łatwa część. Ten kod pokazuje całą instalację wodno-kanalizacyjną.

Edytuj: Zostało zaktualizowane, aby prawidłowo obsługiwać UITextFieldDelegate textField:shouldChangeCharactersInRange:replacementString: i UITextViewDelegate textView:shouldChangeTextInRange:replacementText:.

Plik nagłówka:

@interface SomeKeyboard : UIView <UIInputViewAudioFeedback> 

@end 

Plik realizacja:

@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 

Ta klasa wymaga metody kategoria dla 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 
+0

Znam to stara odpowiedź, ale próbuję twojej odpowiedzi i zauważyłem, że daje mi błąd na [self updateShift] ; Czy to jest metoda, która ma być zawarta w twojej próbce, czy jest z innego źródła? – connor

+0

Możesz wywołać tę metodę. W mojej prawdziwej niestandardowej klawiaturze mam klawisz Shift, który aktualizuję jak klawisz Shift na standardowej domyślnej klawiaturze. To wykracza poza zakres tej odpowiedzi. – rmaddy

+0

dzięki za pomoc. Czy muszę zrobić cokolwiek poza ustawieniem klawiatury jako inputView pola tekstowego? W tej chwili mam wszystko skonfigurowane i przetestowałem, że przechodzi on do metody keyTapped po naciśnięciu przycisku, ale pole tekstowe się nie zmienia – connor

14

Stworzyłem pełną przykład roboczy klawiatura do iPada, dostępna na Github tutaj:

https://github.com/lnafziger/Numberpad

Numberpad to klawiatura zwyczaj numeryczny dla iPada, który współpracuje z zarówno UITextField „s oraz UITextView” s wymagających żadnych zmian innych niż dodawania instancji klasy Numberpad jako inputView tekstu pole/widok.

Cechy:

  • jest objęta licencją MIT, więc może być dowolnie kopiowane i wykorzystywane za jej warunkach.
  • Działa z UITextFields i UITextViews
  • Nie wymaga ustawienia delegata.
  • Automatycznie śledzi, który widok jest pierwszym respondentem (więc nie musisz)
  • Nie musisz ustawiać rozmiaru klawiatury ani jej śledzić.
  • Istnieje współużytkowana instancja, której można użyć dla dowolnej liczby widoków wejściowych, bez potrzeby korzystania z dodatkowej pamięci dla każdego z nich.

Wykorzystanie jest tak proste, jak w tym Numberpad.h a następnie:

theTextField.inputView = [Numberpad defaultNumberpad]; 

Cała reszta jest pod opieką automatycznie!

Albo pobierz dwa pliki klas i plik xib z Github (link powyżej), albo utwórz przyciski (w kodzie lub w serii ujęć/xib) z ich działaniami ustawionymi na odpowiednie metody w klasie (numberpadNumberPressed, numberpadDeletePressed, numberpadClearPressed lub numberpadDonePressed).

Poniższy kod jest nieaktualny. Zobacz projekt Github, aby uzyskać najnowszy kod.

Numberpad.h:

#import <UIKit/UIKit.h> 

@interface Numberpad : UIViewController 

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

@end 

Numberpad.m:

#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 
Powiązane problemy