Jak poruszać się po polach tekstowych (przyciski Next / Done)

Jak mogę poruszać się po wszystkich polach tekstowych za pomocą przycisku "Dalej" na klawiaturze iPhone ' a?

Ostatnie pole tekstowe powinno zamknąć klawiaturę.

Ustawiłem IB przyciski (Next / Done), ale teraz utknąłem.

Zaimplementowałem akcję textFieldShouldReturn, ale teraz przyciski Next I Done zamykają klawiaturę.

Author: picciano, 2009-08-28

30 answers

W Cocoa dla Mac OS X, masz łańcuch next responder, gdzie możesz zapytać pole tekstowe, która kontrola powinna mieć fokus dalej. To sprawia, że tabulowanie między polami tekstowymi działa. Ale ponieważ Urządzenia z systemem iOS nie mają klawiatury, a tylko dotyk, koncepcja ta nie przetrwała przejścia na Cocoa Touch.

I tak można to łatwo zrobić, przy dwóch założeniach:

  1. Wszystkie "tabbable" UITextFieldS są w tym samym widoku nadrzędnym.
  2. ich "tab-order" jest zdefiniowany przez tag własność.

Zakładając, że to możesz przesłaniać textFieldShouldReturn: as this:

-(BOOL)textFieldShouldReturn:(UITextField*)textField
{
  NSInteger nextTag = textField.tag + 1;
  // Try to find next responder
  UIResponder* nextResponder = [textField.superview viewWithTag:nextTag];
  if (nextResponder) {
    // Found next responder, so set it.
    [nextResponder becomeFirstResponder];
  } else {
    // Not found, so remove keyboard.
    [textField resignFirstResponder];
  }
  return NO; // We do not want UITextField to insert line-breaks.
}

Dodaj trochę więcej kodu, A założenia można również zignorować.

Swift 4.0

 func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    let nextTag = textField.tag + 1
    // Try to find next responder
    let nextResponder = textField.superview?.viewWithTag(nextTag) as UIResponder!

    if nextResponder != nil {
        // Found next responder, so set it
        nextResponder?.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard
        textField.resignFirstResponder()
    }

    return false
}

Jeśli superview pola tekstowego będzie uitableviewcell, to następny responder będzie

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
 546
Author: PeyloW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-09 12:58:49

Istnieje dużo bardziej eleganckie rozwiązanie, które rozwaliło mnie, gdy pierwszy raz go zobaczyłem. Korzyści:

  • Closer to OSX textfield implementation where textfield knows where the focus should go next
  • nie polega na ustawianiu lub używaniu znaczników -- które są IMO delikatne w tym przypadku
  • Można go rozszerzyć tak, aby działał zarówno ze sterownikami UITextField, jak i UITextView -- lub dowolnymi sterownikami interfejsu użytkownika klawiatury
  • nie zaśmieca kontrolera widoku za pomocą boilerplate UITextField delegate code
  • dobrze integruje się z IB i może być skonfigurowany za pomocą znanej opcji-drag-drop, aby podłączyć gniazda.

Utwórz podklasę UITextField, która ma właściwość IBOutlet o nazwie nextField. Oto nagłówek:

@interface SOTextField : UITextField

@property (weak, nonatomic) IBOutlet UITextField *nextField; 

@end

A oto implementacja:

@implementation SOTextField

@end

W kontrolerze widoku utworzysz -textFieldShouldReturn: metodę delegate:

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if ([textField isKindOfClass:[SOTextField class]]) {
        UITextField *nextField = [(SOTextField *)textField nextField];

        if (nextField) {
            dispatch_async(dispatch_get_current_queue(), ^{
                [nextField becomeFirstResponder];
            });
        }
        else {
            [textField resignFirstResponder];
        }
    }

    return YES;
}

W IB Zmień UITextFields na klasę SOTextField. Następnie, również w IB, Ustaw deleguj dla każdego z 'Sotextfields' do 'właściciela pliku' (który jest dokładnie tam, gdzie umieszczasz kod dla metody delegate-textFieldShouldReturn). Piękno tego wzoru polega na tym, że teraz możesz po prostu kliknąć prawym przyciskiem myszy na dowolnym polu tekstowym i przypisać gniazdko nextField do następnego obiektu SOTextField, który chcesz być następnym responderem.

Przypisywanie nextField w IB

Co więcej, możesz robić fajne rzeczy, takie jak zapętlać pola tekstowe, aby po tym, jak ostatni utraci fokus, pierwszy otrzyma fokus jeszcze raz.

Można to łatwo rozszerzyć, aby automatycznie przypisać returnKeyType z SOTextField do UIReturnKeyNext, jeśli jest przypisany nextField-jedna rzecz mniej ręcznie skonfigurowana.

 169
Author: memmons,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-27 16:37:49

Oto moje rozwiązanie tego problemu.

Aby rozwiązać ten problem (i ponieważ nie lubię polegać na tagach do robienia rzeczy) postanowiłem dodać właściwość niestandardową do obiektu UITextField. Innymi słowy stworzyłem kategorię na UITextField w ten sposób:

UITextField + Extended.h

@interface UITextField (Extended)

@property(retain, nonatomic)UITextField* nextTextField;

@end

UITextField + Extended.na

#import "UITextField+Extended.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UITextField (Extended)

- (UITextField*) nextTextField { 
    return objc_getAssociatedObject(self, &defaultHashKey); 
}

- (void) setNextTextField:(UITextField *)nextTextField{
    objc_setAssociatedObject(self, &defaultHashKey, nextTextField, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end

Oto jak go używam:

UITextField *textField1 = ...init your textfield
UITextField *textField2 = ...init your textfield
UITextField *textField3 = ...init your textfield

textField1.nextTextField = textField2;
textField2.nextTextField = textField3;
textField3.nextTextField = nil;

I zaimplementować metodę textFieldShouldReturn:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {

    UITextField *next = theTextField.nextTextField;
    if (next) {
        [next becomeFirstResponder];
    } else {
        [theTextField resignFirstResponder];
    }

    return NO; 
}

I teraz mają rodzaj połączonej listy UITextField, każdy z nich wie, kto jest następny w linii.

Mam nadzieję, że to pomoże.
 78
Author: Anth0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-01 16:34:18

Oto jeden bez delegacji:

tf1.addTarget(tf2, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)
tf2.addTarget(tf3, action: #selector(becomeFirstResponder), for: .editingDidEndOnExit)

ObjC:

[tf1 addTarget:tf2 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];
[tf2 addTarget:tf3 action:@selector(becomeFirstResponder) forControlEvents:UIControlEventEditingDidEndOnExit];

Działa przy użyciu (w większości nieznanych) UIControlEventEditingDidEndOnExit UITextField Akcja.

Możesz również łatwo podłączyć to w storyboardzie, więc nie jest wymagany żaden kod delegacji lub.

Edit: właściwie nie mogę wymyślić, jak podłączyć to w storyboardzie. becomeFirstResponder nie wydaje się być oferowanym działaniem dla tego zdarzenia kontrolnego, a szkoda. Mimo to możesz podłączyć wszystkie pola tekstowe do jednej akcji w kontrolerze ViewController które następnie określa, które pole tekstowe do becomeFirstResponder na podstawie nadawcy (choć wtedy nie jest tak eleganckie jak powyższe rozwiązanie programistyczne, więc IMO zrób to z powyższym kodem w viewDidLoad).

 75
Author: mxcl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 22:24:25

Rozszerzenie swift, które stosuje odpowiedź mxcl, aby uczynić to szczególnie łatwym (dostosowane do swift 2.3 by Traveler):

extension UITextField {
    class func connectFields(fields:[UITextField]) -> Void {
        guard let last = fields.last else {
            return
        }
        for i in 0 ..< fields.count - 1 {
            fields[i].returnKeyType = .Next
            fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
        }
        last.returnKeyType = .Done
        last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), forControlEvents: .EditingDidEndOnExit)
    }
}
Jest łatwy w użyciu:
UITextField.connectFields([field1, field2, field3])

Rozszerzenie ustawi przycisk powrotu na "Next" dla wszystkich poza ostatnim polem i na "Done"dla ostatniego pola, a przesunięcie ostrości / odrzucenie klawiatury po naciśnięciu.

Swift

extension UITextField {
    class func connectFields(fields:[UITextField]) -> Void {
        guard let last = fields.last else {
            return
        }
        for var i = 0; i < fields.count - 1; i += 1 {
            fields[i].returnKeyType = .Next
            fields[i].addTarget(fields[i+1], action: "becomeFirstResponder", forControlEvents: .EditingDidEndOnExit)
        }
        last.returnKeyType = .Done
        last.addTarget(last, action: "resignFirstResponder", forControlEvents: .EditingDidEndOnExit)
    }
}

SWIFT 3: użyj w ten sposób -

UITextField.connectFields(fields: [field1, field2])

Extension:
    extension UITextField {
        class func connectFields(fields:[UITextField]) -> Void {
            guard let last = fields.last else {
                return
            }
            for i in 0 ..< fields.count - 1 {
                fields[i].returnKeyType = .next
                fields[i].addTarget(fields[i+1], action: #selector(UIResponder.becomeFirstResponder), for: .editingDidEndOnExit)
            }
            last.returnKeyType = .go
            last.addTarget(last, action: #selector(UIResponder.resignFirstResponder), for: .editingDidEndOnExit)
        }
    }
 43
Author: Amos Joshua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-06 20:49:22

Bardziej spójnym i solidnym sposobem jest użycie NextResponderTextField Możesz go skonfigurować całkowicie z poziomu narzędzia interface builder bez potrzeby ustawiania delegata lub używania view.tag.

Wszystko, co musisz zrobić, to

  1. Ustaw typ klasy twojego UITextField na NextResponderTextField Tutaj wpisz opis obrazka
  2. następnie Ustaw wylot nextResponderField, aby wskazywał następny responder, może to być cokolwiek UITextField lub dowolna podklasa UIResponder. Może to być również UIButton, a Biblioteka jest wystarczająco inteligentna, aby uruchomić TouchUpInside Zdarzenie przycisku tylko jeżeli jest włączone. Tutaj wpisz opis obrazkaTutaj wpisz opis obrazka
Oto Biblioteka w akcji:

Tutaj wpisz opis obrazka

 25
Author: mohamede1945,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-29 04:39:09

Lubię rozwiązania OO, które zostały już zasugerowane przez Anth0 i Answerbot. Jednak pracowałem nad szybkim i małym POC, więc nie chciałem zaśmiecać rzeczy podklasami i kategoriami.

Innym prostym rozwiązaniem jest utworzenie NSArray pól i wyszukanie następnego pola po naciśnięciu next. Nie jest to rozwiązanie OO, ale szybkie, proste i łatwe do wdrożenia. Ponadto możesz zobaczyć i zmodyfikować zamówienie na pierwszy rzut oka.

Oto Mój kod (zbudowany na innych odpowiedziach w tym wątek): {]}

@property (nonatomic) NSArray *fieldArray;

- (void)viewDidLoad {
    [super viewDidLoad];

    fieldArray = [NSArray arrayWithObjects: firstField, secondField, thirdField, nil];
}

- (BOOL) textFieldShouldReturn:(UITextField *) textField {
    BOOL didResign = [textField resignFirstResponder];
    if (!didResign) return NO;

    NSUInteger index = [self.fieldArray indexOfObject:textField];
    if (index == NSNotFound || index + 1 == fieldArray.count) return NO;

    id nextField = [fieldArray objectAtIndex:index + 1];
    activeField = nextField;
    [nextField becomeFirstResponder];

    return NO;
}
  • zawsze zwracam nie, ponieważ nie chcę wstawiać przerwania linii. Po prostu pomyślałem, że wskażę, że od kiedy zwróciłem tak, automatycznie zamknie kolejne pola lub wstawi podział linii w moim widoku tekstowym. Zajęło mi trochę czasu, żeby to rozgryźć.
  • activeField śledzi aktywne pole w przypadku, gdy przewijanie jest konieczne do odblokowania pola z klawiatury. Jeśli masz podobny kod, upewnij się, że przypisałeś activeField przed zmianą pierwsza pomoc. Zmiana pierwszego ratownika jest natychmiastowa i natychmiast uruchomi Zdarzenie KeyboardWasShown.
 14
Author: Marquee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-31 15:12:18

Oto implementacja tabbingu przy użyciu kategorii na UIControl. To rozwiązanie ma wszystkie zalety metod Michaela i Anth0, ale działa dla wszystkich UIControls, nie tylko UITextField s. działa również bezproblemowo z Interface Builder i storyboardami.

Źródło i przykładowa aplikacja: repozytorium GitHub dla UIControlsWithTabbing

Użycie:

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    [textField transferFirstResponderToNextControl];
    return NO;
}

Przypisywanie nextControl w Interface Builder

Nagłówek:

//
// UIControl+NextControl.h
// UIControlsWithTabbing
//

#import <UIKit/UIKit.h>

@interface UIControl (NextControl)

@property (nonatomic, weak) IBOutlet UIControl *nextControl;

- (BOOL)transferFirstResponderToNextControl;

@end

Realizacja:

#import "UIControl+NextControl.h"
#import <objc/runtime.h>

static char defaultHashKey;

@implementation UIControl (NextControl)

- (UIControl *)nextControl
{
    return objc_getAssociatedObject(self, &defaultHashKey);
}

- (void)setNextControl:(UIControl *)nextControl
{
    objc_setAssociatedObject(self, &defaultHashKey, nextControl, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)transferFirstResponderToNextControl
{
    if (self.nextControl)
    {
        [self.nextControl becomeFirstResponder];

        return YES;
    }

    [self resignFirstResponder];

    return NO;
}

@end
 11
Author: picciano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-22 17:13:31

Po wyjściu z jednego pola tekstowego wywołujesz [otherTextField becomeFirstResponder], a następne pole otrzymuje fokus.

W rzeczywistości może to być trudny problem, ponieważ często będziesz chciał przewijać ekran lub w inny sposób dostosować położenie pola tekstowego, aby było łatwe do zobaczenia podczas edycji. Po prostu upewnij się, że wykonasz wiele testów przy wchodzeniu i wychodzeniu z pól tekstowych na różne sposoby, a także wcześnie opuszczasz (zawsze daj użytkownikowi opcję odrzucenia klawiatury zamiast przejść do następnego pola, zwykle z "gotowe" w pasku nav)

 9
Author: Kendall Helmstetter Gelner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-28 20:19:58
 -(BOOL)textFieldShouldReturn:(UITextField *)textField
{
   [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
   return YES;
}
 9
Author: iKushal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 10:42:05

Wypróbowałem wiele kodów i w końcu zadziałało mi to w Swift 3.0 Latest [Marzec 2017]

Klasa ViewController powinna być dziedziczona UITextFieldDelegate, aby ten kod działał.

class ViewController: UIViewController,UITextFieldDelegate  

Dodaj pole tekstowe z odpowiednim numerem znacznika i ten numer znacznika jest używany do przejęcia kontroli nad odpowiednim polem tekstowym na podstawie przypisanego do niego przyrostowego numeru znacznika.

override func viewDidLoad() {
    userNameTextField.delegate = self
    userNameTextField.tag = 0
    userNameTextField.returnKeyType = UIReturnKeyType.next
    passwordTextField.delegate = self
    passwordTextField.tag = 1
    passwordTextField.returnKeyType = UIReturnKeyType.go
}

W powyższym kodzie, returnKeyType = UIReturnKeyType.next gdzie spowoduje, że Klawisz zwróci klawisz do wyświetlenia jako Next również mieć inne opcje jak Join/Go itd, w zależności od aplikacji zmień wartości.

To textFieldShouldReturn jest metodą kontrolowaną przez UITextFieldDelegate i tutaj mamy następny wybór pola na podstawie przyrostu wartości znacznika

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
        nextField.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
        return true;
    }
    return false
 }
 8
Author: BHUVANESH MOHANKUMAR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-16 15:30:30

Jestem zaskoczony tym, jak wiele odpowiedzi tutaj nie rozumie jednej prostej koncepcji: nawigowanie po kontrolkach w aplikacji nie jest czymś, co same widoki powinny zrobić. Zadaniem kontrolera jest podjęcie decyzji, który kontroler ma wykonać następny.

Również większość odpowiedzi dotyczy tylko nawigacji do przodu, ale użytkownicy mogą również chcieć cofnąć się.

Oto, co wymyśliłem. Formularzem powinien zarządzać kontroler widoku, a Kontrolery widoku to część łańcucha respondentów. Więc możesz całkowicie swobodnie wdrażać następujące metody:
#pragma mark - Key Commands

- (NSArray *)keyCommands
{
    static NSArray *commands;

    static dispatch_once_t once;
    dispatch_once(&once, ^{
        UIKeyCommand *const forward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:0 action:@selector(tabForward:)];
        UIKeyCommand *const backward = [UIKeyCommand keyCommandWithInput:@"\t" modifierFlags:UIKeyModifierShift action:@selector(tabBackward:)];

        commands = @[forward, backward];
    });

    return commands;
}

- (void)tabForward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.firstObject becomeFirstResponder];
}

- (void)tabBackward:(UIKeyCommand *)command
{
    NSArray *const controls = self.controls;
    UIResponder *firstResponder = nil;

    for (UIResponder *const responder in controls.reverseObjectEnumerator) {
        if (firstResponder != nil && responder.canBecomeFirstResponder) {
            [responder becomeFirstResponder]; return;
        }
        else if (responder.isFirstResponder) {
            firstResponder = responder;
        }
    }

    [controls.lastObject becomeFirstResponder];
}

Może zostać zastosowana dodatkowa logika przewijania ekranów wyświetlanych wcześniej.

Kolejną zaletą tego podejścia jest to, że nie musisz podklasować WSZYSTKICH rodzajów kontrolek, które chcesz wyświetlić (jak UITextField s), ale zamiast tego możesz zarządzać logiką na poziomie kontrolera, gdzie, bądźmy szczerzy, jest właściwe miejsce, aby to zrobić.

 7
Author: Christian Schnorr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-16 17:28:49

Bardzo łatwą metodą na oddalenie klawiatury po naciśnięciu przycisku "Gotowe" jest:

Utwórz nową IBAction w nagłówku

- (IBAction)textFieldDoneEditing:(id)sender;

W pliku implementacji (.plik m) dodać następującą metodę:

- (IBAction)textFieldDoneEditing:(id)sender 
{ 
  [sender resignFirstResponder];
}

Następnie, gdy przyjdzie połączyć IBAction do textfield-link do zdarzenia "Did End On Exit".

 6
Author: jcrowson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-23 09:54:07

Najpierw ustaw klawisz powrotu klawisza w xib, w przeciwnym razie możesz napisać kod w viewdidload:

passWord.returnKeyType = UIReturnKeyNext;

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
    if(textField == eMail) {
        [textField resignFirstResponder];
        [userName becomeFirstResponder];
    }
    if (textField==userName) {
        [textField resignFirstResponder];
        [passWord becomeFirstResponder];
    }
    if (textField==passWord) {
        [textField resignFirstResponder];
        [country becomeFirstResponder];
    }
    if (textField==country) {
        [textField resignFirstResponder];
    }
    return YES;
}
 6
Author: mahesh chowdary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-03 21:34:28

Dodałem do odpowiedzi Peylowa w przypadku, gdy chcesz zaimplementować funkcję Poprzedni / Następny przycisk:

- (IBAction)moveThroughTextFields:(UIBarButtonItem *)sender 
{
    NSInteger nextTag;
    UITextView *currentTextField = [self.view findFirstResponderAndReturn];

    if (currentTextField != nil) {
        // I assigned tags to the buttons.  0 represent prev & 1 represents next
        if (sender.tag == 0) {
            nextTag = currentTextField.tag - 1;

        } else if (sender.tag == 1) {
            nextTag = currentTextField.tag + 1;
        }
    }
    // Try to find next responder
    UIResponder* nextResponder = [self.view viewWithTag:nextTag];
    if (nextResponder) {
        // Found next responder, so set it.
        // I added the resign here in case there's different keyboards in place.
        [currentTextField resignFirstResponder];
        [nextResponder becomeFirstResponder];
    } else {
        // Not found, so remove keyboard.
        [currentTextField resignFirstResponder];

    }
}

Gdzie podklasujesz UIView TAK:

@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
    for (UITextView *subView in self.subviews) {
        if (subView.isFirstResponder){
            return subView;
        }
    }
    return nil;
}
@end
 4
Author: KronoS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 10:42:37

Witam wszystkich zapraszam do obejrzenia tego

- (void)nextPrevious:(id)sender
{

  UIView *responder = [self.view findFirstResponder];   

  if (nil == responder || ![responder isKindOfClass:[GroupTextField class]]) {
    return;
  }

  switch([(UISegmentedControl *)sender selectedSegmentIndex]) {
    case 0:
      // previous
      if (nil != ((GroupTextField *)responder).previousControl) {
        [((GroupTextField *)responder).previousControl becomeFirstResponder];
        DebugLog(@"currentControl: %i previousControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).previousControl.tag);
      }
      break;
    case 1:
      // next
      if (nil != ((GroupTextField *)responder).nextControl) {
        [((GroupTextField *)responder).nextControl becomeFirstResponder];
        DebugLog(@"currentControl: %i nextControl: %i",((GroupTextField *)responder).tag,((GroupTextField *)responder).nextControl.tag);
      }     
      break;    
  }
}
 4
Author: rithik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-24 10:43:39

Próbowałem rozwiązać ten problem przy użyciu bardziej wyrafinowanego podejścia opartego na przypisaniu każdej komórki (lub UITextField) w UITableView unikalnej wartości znacznika, którą można później pobrać: activate-next-UITextField-in-UITableView-ios

Mam nadzieję, że to pomoże!
 4
Author: Fabiano Francesconi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-14 12:04:17

Właśnie stworzyłem nowy Pod, gdy radziłem sobie z tymi rzeczami GNTextFieldsCollectionManager. Automatycznie obsługuje problem next/last textField i jest bardzo łatwy w użyciu:

[[GNTextFieldsCollectionManager alloc] initWithView:self.view];

Chwyta wszystkie pola tekstowe posortowane według hierarchii widoków (lub według tagów), lub możesz określić własną tablicę pól tekstowych.

 4
Author: JakubKnejzlik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 10:24:20

Ja raczej wolę:

@interface MyViewController : UIViewController
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *inputFields;
@end

W pliku NIB podłączam pola tekstowe w żądanej kolejności do tablicy inputFields. Następnie wykonuję prosty test dla indeksu UITextField, który zgłasza, że użytkownik stuknął return:

// for UITextField
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
    NSUInteger index = [_inputFields indexOfObject:textField];
    index++;
    if (index < _inputFields.count) {
        UIView *v = [_inputFields objectAtIndex:index];
        [v becomeFirstResponder];
    }
    return NO;
}

// for UITextView
-(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
    if ([@"\n" isEqualToString:text]) {
        NSUInteger index = [_inputFields indexOfObject:textView];
        index++;
        if (index < _inputFields.count) {
            UIView *v = [_inputFields objectAtIndex:index];
            [v becomeFirstResponder];
        } else {
            [self.view endEditing:YES];
        }
        return NO;
    }
    return YES;
}
 3
Author: Anticro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-26 09:34:38
if (cell == nil)
{
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    txt_Input = [[ UITextField alloc] initWithFrame:CGRectMake(0, 10, 150, 30)];
    txt_Input.tag = indexPath.row+1;
    [self.array_Textfields addObject:txt_Input]; // Initialize mutable array in ViewDidLoad
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField
{

    int tag = ( int) textField.tag ;
    UITextField * txt = [  self.array_Textfields objectAtIndex:tag ] ;
    [ txt becomeFirstResponder] ;
    return YES ;
}
 3
Author: Rebecca Curties,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 10:04:31

Miałem około 10 + UITextField w mojej tablicy historii i sposób włączyłem następną funkcjonalność było tworzenie tablicy UITextField i co następny UITextField pierwszy responder. Oto plik implementacji:

#import "RegistrationTableViewController.h"

@interface RegistrationTableViewController ()
@property (weak, nonatomic) IBOutlet UITextField *fullNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *addressTextField;
@property (weak, nonatomic) IBOutlet UITextField *address2TextField;
@property (weak, nonatomic) IBOutlet UITextField *cityTextField;
@property (weak, nonatomic) IBOutlet UITextField *zipCodeTextField;
@property (weak, nonatomic) IBOutlet UITextField *urlTextField;
@property (weak, nonatomic) IBOutlet UITextField *usernameTextField;
@property (weak, nonatomic) IBOutlet UITextField *emailTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
@property (weak, nonatomic) IBOutlet UITextField *confirmPWTextField;

@end
NSArray *uiTextFieldArray;
@implementation RegistrationTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"view did load");
    uiTextFieldArray = @[self.fullNameTextField,self.addressTextField,self.address2TextField,self.cityTextField,self.zipCodeTextField,self.urlTextField,self.usernameTextField,self.emailTextField,self.passwordTextField,self.confirmPWTextField];
    for(UITextField *myField in uiTextFieldArray){
        myField.delegate = self;
    }


}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    long index = [uiTextFieldArray indexOfObject:textField];
    NSLog(@"%ld",index);
    if(index < (uiTextFieldArray.count - 1)){
        [uiTextFieldArray[++index] becomeFirstResponder];
    }else{
        [uiTextFieldArray[index] resignFirstResponder];
    }
    return YES;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
 3
Author: Illegal Argument,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-04 10:06:07

To zadziałało u mnie w Xamarin.iOS / Monotouch. Zmień przycisk klawiatury na Next, przekaż sterowanie do następnego UITextField i ukryj klawiaturę po ostatnim UITextField.

private void SetShouldReturnDelegates(IEnumerable<UIView> subViewsToScout )
{
  foreach (var item in subViewsToScout.Where(item => item.GetType() == typeof (UITextField)))
  {
    (item as UITextField).ReturnKeyType = UIReturnKeyType.Next;
    (item as UITextField).ShouldReturn += (textField) =>
    {
        nint nextTag = textField.Tag + 1;
        var nextResponder = textField.Superview.ViewWithTag(nextTag);
        if (null != nextResponder)
            nextResponder.BecomeFirstResponder();
        else
            textField.Superview.EndEditing(true); 
            //You could also use textField.ResignFirstResponder(); 

        return false; // We do not want UITextField to insert line-breaks.
    };
  }
}

Wewnątrz ViewDidLoad będziesz miał:

If your TextFields haven ' t a Tag set it now:

txtField1.Tag = 0;
txtField2.Tag = 1;
txtField3.Tag = 2;
//...

I tylko wezwanie

SetShouldReturnDelegates(yourViewWithTxtFields.Subviews.ToList());
//If you are not sure of which view contains your fields you can also call it in a safer way:
SetShouldReturnDelegates(txtField1.Superview.Subviews.ToList());
//You can also reuse the same method with different containerViews in case your UITextField are under different views.
 3
Author: Daniele D.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 16:27:44

Jest to proste rozwiązanie w języku swift, bez użycia tagów, bez sztuczek storyboardowych...

Po prostu użyj tego rozszerzenia:

extension UITextField{

    func nextTextFieldField() -> UITextField?{
        //field to return
        var returnField : UITextField?
        if self.superview != nil{
            //for each view in superview
            for (_, view) in self.superview!.subviews.enumerate(){
                //if subview is a text's field
                if view.isKindOfClass(UITextField){
                    //cast curent view as text field
                    let currentTextField = view as! UITextField
                    //if text field is after the current one
                    if currentTextField.frame.origin.y > self.frame.origin.y{
                        //if there is no text field to return already
                        if returnField == nil {
                            //set as default return
                            returnField = currentTextField
                        }
                            //else if this this less far than the other
                        else if currentTextField.frame.origin.y < returnField!.frame.origin.y{
                            //this is the field to return
                            returnField = currentTextField
                        }
                    }
                }
            }
        }
        //end of the mdethod
        return returnField
    }

}

I nazwij to tak (na przykład) delegatem textfield:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}
 3
Author: Kevin ABRIOUX,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 11:03:37

Rozwiązanie w Swift 3.1, po podłączeniu pól tekstowych iboutlets Ustaw delegata pól tekstowych w viewDidLoad, a następnie Nawiguj swoją akcję w textFieldShouldReturn

class YourViewController: UIViewController,UITextFieldDelegate {

        @IBOutlet weak var passwordTextField: UITextField!
        @IBOutlet weak var phoneTextField: UITextField!

        override func viewDidLoad() {
            super.viewDidLoad()
            self.passwordTextField.delegate = self
            self.phoneTextField.delegate = self
            // Set your return type
            self.phoneTextField.returnKeyType = .next
            self.passwordTextField.returnKeyType = .done
        }

        func textFieldShouldReturn(_ textField: UITextField) -> Bool{
            if textField == self.phoneTextField {
                self.passwordTextField.becomeFirstResponder()
            }else if textField == self.passwordTextField{
                // Call login api
                self.login()
            }
            return true
        }

    }
 3
Author: Krishna Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-25 08:06:44

W textFieldShouldReturn powinieneś sprawdzić, czy pole tekstowe, na którym aktualnie jesteś, nie jest ostatnim, gdy klikniesz dalej i jeśli nie zamkniesz klawiatury..

 2
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-28 15:49:38

To jest stary post, ale ma wysoki page rank więc będę grzeczny z moim rozwiązaniem.

Miałem podobny problem i skończyłem tworząc podklasę UIToolbar do zarządzania funkcjami następny / poprzedni/zrobione w dynamicznym widoku tableView z sekcjami: https://github.com/jday001/DataEntryToolbar

Ustawiasz pasek narzędzi jako inputAccessoryView pól tekstowych i dodajesz je do słownika. Pozwala to na przełączanie się między nimi do przodu i do tyłu, nawet w przypadku dynamicznej zawartości. Istnieją metody delegowania, jeśli chcesz uruchomić własną funkcjonalność podczas nawigacji w polu tekstowym, ale nie musisz zajmować się zarządzaniem znacznikami lub statusem pierwszej odpowiedzi.

W linku GitHub znajdują się fragmenty kodu i przykładowa aplikacja, która pomaga w szczegółach implementacji. Do śledzenia wartości wewnątrz pól potrzebny jest własny model danych.

 2
Author: jday,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-26 21:35:50

Bez użycia znaczników i bez dodawania właściwości dla nextField/nextTextField, możesz spróbować emulować TAB, gdzie "testInput"jest Twoim bieżącym aktywnym polem:

if ([textInput isFirstResponder])
    [textInput.superview.subviews enumerateObjectsAtIndexes:
     [NSIndexSet indexSetWithIndexesInRange:
      NSMakeRange([textInput.superview.subviews indexOfObject:textInput]+1,
                  [textInput.superview.subviews count]-[textInput.superview.subviews indexOfObject:textInput]-1)]
                                                    options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                        *stop = !obj.hidden && [obj becomeFirstResponder];
                                                    }];
if ([textInput isFirstResponder])
    [textInput.superview.subviews enumerateObjectsAtIndexes:
     [NSIndexSet indexSetWithIndexesInRange:
      NSMakeRange(0,
                  [textInput.superview.subviews indexOfObject:textInput])]
                                                    options:0 usingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
                                                        *stop = !obj.hidden && [obj becomeFirstResponder];
                                                    }];
 2
Author: Cœur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-14 11:47:28

Używam odpowiedzi Michaela G. Emmonsa od około roku, działa świetnie. Zauważyłem ostatnio, że wywołanie resignFirstResponder, a następnie natychmiast stać się pierwszym respondentem, może spowodować "usterkę" klawiatury, zniknięcie, a następnie natychmiastowe pojawienie się. Zmieniłem nieco jego wersję, aby pominąć resignFirstResponder, jeśli następne pole jest dostępne.

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{ 

    if ([textField isKindOfClass:[NRTextField class]])
    {
        NRTextField *nText = (NRTextField*)textField;
        if ([nText nextField] != nil){
            dispatch_async(dispatch_get_main_queue(),
                           ^ { [[nText nextField] becomeFirstResponder]; });

        }
        else{
            [textField resignFirstResponder];
        }
    }
    else{
        [textField resignFirstResponder];
    }

    return true;

}
 2
Author: arinmorf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-18 02:34:44

Możesz użyć biblioteki IQKeyboardManager. obsługuje każdą rzecz, nie potrzebujesz żadnej dodatkowej konfiguracji.IQKeyboardManager jest dostępny przez CocoaPods, aby go zainstalować wystarczy dodać następującą linię do pliku Podfile:

pod 'IQKeyboardManager'

Lub Wystarczy przeciągnąć i upuścić katalog IQKeyBoardManager z projektu demo do swojego projektu. To wszystko. możesz znaleźć katalog IQKeyBoardManager z https://github.com/hackiftekhar/IQKeyboardManager

 2
Author: Amit Shelgaonkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-22 12:42:46

Oto wersja Swift 3 odpowiedzi Anth0 . Zamieszczam go tutaj, aby pomóc dowolnym programistom swift w chęci skorzystania z jego świetnej odpowiedzi! Pozwoliłem sobie dodać klawisz return typu "Next", gdy ustawiasz skojarzony obiekt.

extension UITextField {

  @nonobjc static var NextHashKey: UniChar = 0

  var nextTextField: UITextField? {
    get {
      return objc_getAssociatedObject(self, 
        &UITextField.NextHashKey) as? UITextField
    }
    set(next) {
     self.returnKeyType = UIReturnKeyType.next
     objc_setAssociatedObject(self,
      &UITextField.NextHashKey,next,.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
  }
}

Oto kolejne rozszerzenie, które pokazuje możliwość użycia powyższego kodu do przełączania się przez Listę UITextFields.

extension UIViewController: UITextFieldDelegate {
 public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
   guard let next = textField.nextTextField else {
     textField.resignFirstResponder()
     return true
   }

    next.becomeFirstResponder()
    return false
  }
}

A następnie w kontrolerze ViewController lub gdziekolwiek indziej, możesz ustawić swoje pola tekstowe, takie jak więc...

@IBOutlet fileprivate weak var textfield1: UITextField!
@IBOutlet fileprivate weak var textfield2: UITextField!
@IBOutlet fileprivate weak var textfield3: UITextField!

...

[textfield1, textfield2, textfield3].forEach{ $0?.delegate = self }

textfield1.nextTextField = textfield2
textfield2.nextTextField = textfield3
// We don't assign a nextTextField to textfield3 because we want 
// textfield3 to be the last one and resignFirstResponder when 
// the return button on the soft keyboard is tapped.
 2
Author: Justin Wright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-23 15:03:15