it-swarm.com.de

So navigieren Sie durch Textfelder (Schaltflächen Weiter/Fertig)

Wie kann ich mit der Schaltfläche "Weiter" auf der iPhone-Tastatur durch alle meine Textfelder navigieren?

Das letzte Textfeld sollte die Tastatur schließen.

Ich habe die IB die Buttons eingerichtet (Next/Done), aber jetzt stecke ich fest.

Ich habe die Aktion textFieldShouldReturn implementiert, jetzt schließen die Schaltflächen Weiter und Fertig die Tastatur.

469
phx

In Cocoa für Mac OS X haben Sie die nächste Responder-Kette, in der Sie das Textfeld abfragen können, welches Steuerelement als Nächstes den Fokus haben soll. Dies bewirkt, dass das Tabgen zwischen Textfeldern funktioniert. Da iOS-Geräte jedoch keine Tastatur, sondern nur Berührung haben, hat dieses Konzept den Übergang zu Cocoa Touch nicht überstanden.

Dies kann mit zwei Annahmen trotzdem leicht gemacht werden:

  1. Alle "tabbar" UITextFields befinden sich in derselben übergeordneten Ansicht.
  2. Ihre "Tab-Reihenfolge" wird durch die Tag-Eigenschaft definiert.

Angenommen, Sie können textFieldShouldReturn: wie folgt überschreiben:

-(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.
}

Fügen Sie weiteren Code hinzu, und die Annahmen können ebenfalls ignoriert werden.

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
}

Wenn der Überblick über das Textfeld eine UITableViewCell sein wird, ist der nächste Antwortende

let nextResponder = textField.superview?.superview?.superview?.viewWithTag(nextTag) as UIResponder!
557
PeyloW

Es gibt eine viel elegantere Lösung, die mich beim ersten Mal umgehauen hat. Leistungen:

  • Näher an der OSX-Textfeldimplementierung, bei der ein Textfeld weiß, wo der Fokus als nächstes liegen soll
  • Verlässt sich nicht darauf, Tags zu setzen oder zu verwenden - was IMO für diesen Anwendungsfall anfällig ist
  • Kann erweitert werden, um mit UITextField- und UITextView-Steuerelementen zu arbeiten - oder mit einem beliebigen UI-Steuerelement für die Tastatureingabe
  • Der View-Controller wird nicht mit Boilerplate-UITextField-Delegatencode überspielt
  • Integriert sich nahtlos in IB und kann mit der bekannten Option per Drag-Drop zum Verbinden von Steckdosen konfiguriert werden.

Erstellen Sie eine UITextField-Unterklasse, die über eine IBOutlet-Eigenschaft namens nextField verfügt. Hier ist der Header:

@interface SOTextField : UITextField

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

@end

Und hier ist die Implementierung:

@implementation SOTextField

@end

In Ihrem Ansichtscontroller erstellen Sie die Delegatmethode -textFieldShouldReturn::

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

Ändern Sie in IB Ihre UITextFields, um die SOTextField-Klasse zu verwenden. Als nächstes setzen Sie, ebenfalls in IB, den Delegaten für jeden der 'SOTextFields'to-Besitzer der Datei' (wo Sie den Code für die Delegatmethode - textFieldShouldReturn - angeben). Das Schöne an diesem Design ist, dass Sie jetzt einfach mit der rechten Maustaste auf ein beliebiges textField klicken und den nextField-Auslass dem nächsten SOTextField-Objekt zuordnen können, das Sie als nächster Responder verwenden möchten. 

Assigning nextField in IB

Darüber hinaus können Sie coole Dinge wie das Schleifen der TextFields ausführen, so dass nach dem letzten Fokus der Fokus das erste wieder den Fokus erhält.

Dies kann leicht erweitert werden, um die returnKeyType der SOTextField automatisch einer UIReturnKeyNext zuzuweisen, wenn ein nextField zugewiesen ist - eine Sache weniger manuell konfigurieren.

169
memmons

Hier ist meine Lösung für dieses Problem.

Um dieses Problem zu lösen (und weil ich es hasse, mich auf Tags zu verlassen, um Dinge zu tun), entschied ich mich, dem UITextField-Objekt eine benutzerdefinierte Eigenschaft hinzuzufügen. Mit anderen Worten, ich habe eine Kategorie in UITextField erstellt:

UITextField + Extended.h

@interface UITextField (Extended)

@property(retain, nonatomic)UITextField* nextTextField;

@end

UITextField + Extended.m

#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

Nun, so benutze ich es:

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

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

Und implementieren Sie die textFieldShouldReturn-Methode:

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

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

    return NO; 
}

Ich habe jetzt eine Art verknüpfte Liste von UITextField, von denen jeder weiß, wer als nächstes in der Zeile steht.

Ich hoffe es hilft.

78
Anth0

Hier ist eine ohne Delegation:

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

Funktioniert mit der (meist unbekannten) UIControlEventEditingDidEndOnExitUITextField-Aktion.

Sie können dies auch problemlos im Storyboard verknüpfen, sodass kein oderDelegierungscode erforderlich ist.

Edit: Eigentlich kann ich nicht herausfinden, wie ich das im Storyboard anschließen kann. becomeFirstResponder scheint keine angebotene Aktion für dieses Kontrollereignis zu sein, was schade ist. Sie können jedoch alle Ihre Textfelder mit einer einzigen Aktion in Ihrem ViewController verknüpfen, die dann bestimmt, welches textField becomeFirstResponder basierend auf dem Sender ist (obwohl es dann nicht so elegant ist wie die oben genannte programmatische Lösung, so dass IMO es mit dem über dem Code in viewDidLoad).

76
mxcl

Eine Swift-Erweiterung, die die Antwort von mxcl anwendet, um dies besonders einfach zu machen (angepasst an Swift 2.3 von 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)
    }
}

Es ist einfach zu bedienen:

UITextField.connectFields([field1, field2, field3])

Die Erweiterung setzt den Return-Button für alle außer dem letzten Feld auf "Next" und für das letzte Feld auf "Done" und wechselt den Fokus bzw. die Tastatur, wenn diese getippt werden.

Swift <2.3

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: Verwendung wie folgt - 

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)
        }
    }
45
Amos Joshua

Eine konsistentere und robustere Methode ist die Verwendung von NextResponderTextField Sie können sie vollständig vom Interface Builder aus konfigurieren, ohne dass Sie den Delegaten festlegen oder view.tag verwenden müssen.

Alles was Sie tun müssen, ist 

  1. Stellen Sie den Klassentyp Ihrer UITextField auf NextResponderTextFieldenter image description here
  2. Stellen Sie dann den Ausgang der nextResponderField so ein, dass er auf den nächsten Antwortenden zeigt. Dies kann eine beliebige UITextField- oder eine beliebige UIResponder-Unterklasse sein. Es kann auch ein UIButton sein und die Bibliothek ist intelligent genug, um das TouchUpInside -Ereignis der Schaltfläche nur dann auszulösen, wenn sie aktiviert ist .enter image description hereenter image description here

Hier ist die Bibliothek in Aktion:

enter image description here

25
mohamede1945

Ich mag die OO Lösungen, die bereits von Anth0 und Answerbot vorgeschlagen wurden. Ich arbeitete jedoch an einem schnellen und kleinen POC, daher wollte ich nicht mit Unterklassen und Kategorien herumspielen.

Eine andere einfache Lösung besteht darin, ein NSArray von Feldern zu erstellen und das nächste Feld nachzuschlagen, wenn Sie auf Weiter drücken. Keine OO Lösung, aber schnell, einfach und leicht zu implementieren. Außerdem können Sie die Bestellung auf einen Blick sehen und ändern. 

Hier ist mein Code (basierend auf anderen Antworten in diesem Thread):

@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;
}
  • Ich gebe immer NEIN zurück, weil ich keinen Zeilenumbruch einfügen möchte. Ich dachte nur, ich würde darauf hinweisen, denn als ich JA zurückgab, würde ich automatisch die nachfolgenden Felder verlassen oder einen Zeilenumbruch in meine Textansicht einfügen. Ich habe etwas Zeit gebraucht, um das herauszufinden.
  • activeField verfolgt das aktive Feld, falls ein Scrollen erforderlich ist, um das Feld von der Tastatur zu entfernen. Wenn Sie über einen ähnlichen Code verfügen, stellen Sie sicher, dass Sie das activeField zuweisen, bevor Sie den ersten Responder ändern. Der Ersthelfer muss sofort gewechselt werden und das KeyboardWasShown-Ereignis wird sofort ausgelöst.
14
Marquee

Hier ist eine Implementierung von Tabs mit einer Kategorie in UIControl. Diese Lösung bietet alle Vorteile der Methoden von Michael und Anth0, funktioniert jedoch für alle UIControls und nicht nur für UITextFields. Es funktioniert auch nahtlos mit Interface Builder und Storyboards.

Quell- und Beispiel-App: GitHub-Repository für UIControlsWithTabbing

Verwendungszweck:

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

Assigning nextControl in Interface Builder

Header:

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

#import <UIKit/UIKit.h>

@interface UIControl (NextControl)

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

- (BOOL)transferFirstResponderToNextControl;

@end

Implementierung:

#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
picciano

Ich habe schon viele Codes ausprobiert und schließlich funktionierte das für mich in Swift 3.0 Latest [March 2017]

Die ViewController-Klasse sollte von der UITextFieldDelegate geerbt werden, damit dieser Code funktioniert.

class ViewController: UIViewController,UITextFieldDelegate  

Fügen Sie das Textfeld mit der richtigen Tag-Nummer hinzu. Diese Tag-Nummer wird verwendet, um das Steuerelement auf der Grundlage der ihm zugewiesenen inkrementellen Tag-Nummer in das entsprechende Textfeld zu bringen.

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

Im obigen Code wird durch die Angabe von returnKeyType = UIReturnKeyType.next die Rücktaste der Tastatur als Next angezeigt. Sie haben auch andere Optionen als Join/Go usw., je nach Ihrer Anwendung ändern Sie die Werte.

Diese textFieldShouldReturn ist eine von UITextFieldDelegate kontrollierte Methode. Hier haben wir die nächste Feldauswahl basierend auf der Inkrementierung des Tag-Werts

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
 }
10

Nachdem Sie ein Textfeld verlassen haben, rufen Sie [otherTextField becomeFirstResponder] auf und das nächste Feld erhält den Fokus.

Dies kann tatsächlich ein schwieriges Problem sein, mit dem man sich befassen muss, da häufig auch der Bildschirm gescrollt oder die Position des Textfelds auf andere Weise angepasst werden muss, um bei der Bearbeitung leicht zu sehen. Stellen Sie sicher, dass Sie viele Tests durchführen, indem Sie auf verschiedene Weise in die Textfelder ein- und aussteigen und auch früher gehen (geben Sie dem Benutzer immer die Möglichkeit, die Tastatur zu schließen, anstatt zum nächsten Feld zu gehen, normalerweise mit "Done" in die Navigationsleiste) 

 -(BOOL)textFieldShouldReturn:(UITextField *)textField
{
   [[self.view viewWithTag:textField.tag+1] becomeFirstResponder];
   return YES;
}
9
iKushal

Eine sehr einfache Methode, um die Tastatur zu schließen, wenn die Schaltfläche "Fertig" gedrückt wird, ist:

Erstellen Sie eine neue IBAction in der Kopfzeile

- (IBAction)textFieldDoneEditing:(id)sender;

Fügen Sie in der Implementierungsdatei (.m-Datei) die folgende Methode hinzu:

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

Wenn Sie dann die IBAction mit dem Textfeld verknüpfen möchten, klicken Sie auf das Ereignis 'Did End On Exit'.

7
jcrowson

Ich bin überrascht, wie viele Antworten hier ein einfaches Konzept nicht verstehen: Das Navigieren durch Steuerelemente in Ihrer App sollte nicht von den Ansichten selbst ausgeführt werden. Es ist die Aufgabe von Controller, zu entscheiden, welche Steuerung der nächste Ersthelfer sein soll.

Auch galten die meisten Antworten nur für die Navigation vorwärts, aber Benutzer möchten möglicherweise auch rückwärts navigieren.

Also hier ist, was ich mir ausgedacht habe. Ihr Formular sollte von einem Ansichtscontroller verwaltet werden, und Ansichtscontroller sind Teil der Antwortkette. Es steht Ihnen also völlig frei, die folgenden Methoden zu implementieren:

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

Möglicherweise gilt eine zusätzliche Logik für das Scrollen von zuvor sichtbaren Offscreen-Respondern.

Ein weiterer Vorteil dieses Ansatzes besteht darin, dass Sie nicht alle Arten von Steuerelementen, die Sie möglicherweise anzeigen möchten (wie UITextFields), in Unterklassen unterteilen müssen, sondern stattdessen die Logik auf Controller-Ebene verwalten können der richtige Ort dazu.

7

Setzen Sie zuerst die Eingabetaste der Tastatur in xib, andernfalls können Sie Code in viewdidload schreiben:

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
mahesh chowdary

Ich habe gerade einen neuen Pod erstellt, als ich mit diesem Zeug GNTextFieldsCollectionManager fertig wurde. Es behandelt automatisch das nächste/letzte textField-Problem und ist sehr einfach zu bedienen:

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

Erfasst alle Textfelder, die nach Ansicht in der Ansichtshierarchie (oder nach Tags) sortiert sind, oder Sie können ein eigenes Array von textFields angeben.

4
JakubKnejzlik

Lösung in Swift 3.1, Nachdem Sie Ihre Textfelder verbunden haben, setzen IBOutlets Ihren Delegaten für Textfelder in viewDidLoad und navigieren Sie dann in textFieldShouldReturn durch Ihre Aktion

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
        }

    }
4
Krishna Thakur

Hallo an alle bitte sehen dieses hier

- (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
rithik

Ich habe versucht, dieses Problem mit einem komplexeren Ansatz zu lösen, der darauf basiert, jeder Zelle (oder UITextField) einer UITableView einen eindeutigen Tag-Wert zuzuweisen, der später abgerufen werden kann: enable-next-uitextfield-in-uitableview-ios

Ich hoffe das hilft!

4

Ich habe die Antwort von PeyloW hinzugefügt, falls Sie vorige/nächste Tastenfunktionen implementieren möchten:

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

    }
}

Wo Sie die UIView wie folgt unterteilen:

@implementation UIView (FindAndReturnFirstResponder)
- (UITextView *)findFirstResponderAndReturn
{
    for (UITextView *subView in self.subviews) {
        if (subView.isFirstResponder){
            return subView;
        }
    }
    return nil;
}
@end
4
James Mertz

Dies funktionierte für mich in Xamarin.iOS/Monotouch . Ändern Sie die Tastaturschaltfläche in Next, übergeben Sie das Steuerelement an das nächste UITextField und verbergen Sie die Tastatur nach dem letzten 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.
    };
  }
}

Innerhalb von ViewDidLoad haben Sie:

Wenn für Ihre TextFields kein Tag festgelegt wurde:

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

und nur der Anruf

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
Daniele D.

Dies ist eine einfache Lösung in Swift, ohne Verwendung eines Tags, ohne Storyboard-Tricks ...

Verwenden Sie einfach diese Erweiterung:

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
    }

}

Und nennen Sie es mit Ihrem Textfeld-Delegierten so (zum Beispiel):

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    textField.nextTextFieldField()?.becomeFirstResponder()
    return true
}
3
Kevin ABRIOUX

Ich bevorzuge lieber:

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

In der NIB-Datei hänge ich die textFields in der gewünschten Reihenfolge in dieses inputFields-Array ein. Danach führe ich einen einfachen Test für den Index des UITextFields aus, der meldet, dass der Benutzer auf getippt wurde:

// 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
Anticro
if (Zelle == null) 
 {
 cell = [[UITableViewCell-Zuordnung] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: cellIdentifier]; 
 txt_Input = [[UITextField-Zuordnung] initWithFrame: CGRectMake (0, 10, 150, 30)]; 
 txt_Input.tag = indexPath.row + 1; 
 [self.array_Textfields addObject: txt_Input]; // Initialisiere das veränderbare Array in ViewDidLoad 
} 

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

 int tag = (int) textField.tag; 
 UITextField * txt = [self.array_Textfields objectAtIndex: tag]; 
 [txt becomeFirstResponder]; 
 Rückgabe YES; 
} 
3
Rebecca Curties

Ich hatte mehr als 10 UITextField in meinem Storyboard, und die nächste Funktion wurde aktiviert, indem ein Array von UITextField erstellt wurde und das nächste UITextField zum ersten Antworter wurde. Hier ist die Implementierungsdatei:

#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

Wenn jemand so will. Ich denke, dass dies den gestellten Anforderungen am nächsten kommt 

 enter image description here

So habe ich dieses umgesetzt

Fügen Sie für jedes Textfeld, für das Sie das Setup einrichten möchten, eine Zubehöransicht hinzu 

func setAccessoryViewFor(textField : UITextField)    {
    let toolBar = UIToolbar()
    toolBar.barStyle = .default
    toolBar.isTranslucent = true
    toolBar.sizeToFit()

    // Adds the buttons

    // Add previousButton
    let prevButton = UIBarButtonItem(title: "<", style: .plain, target: self, action: #selector(previousPressed(sender:)))
    prevButton.tag = textField.tag
    if getPreviousResponderFor(tag: textField.tag) == nil {
        prevButton.isEnabled = false
    }

    // Add nextButton
    let nextButton = UIBarButtonItem(title: ">", style: .plain, target: self, action: #selector(nextPressed(sender:)))
    nextButton.tag = textField.tag
    if getNextResponderFor(tag: textField.tag) == nil {
        nextButton.title = "Done"
    }

    let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
    toolBar.setItems([prevButton,spaceButton,nextButton], animated: false)
    toolBar.isUserInteractionEnabled = true
    textField.inputAccessoryView = toolBar
}

Verwenden Sie die folgenden Funktionen, um Taps zu behandeln 

func nextPressed(sender : UIBarButtonItem) {
    if let nextResponder = getNextResponderFor(tag: sender.tag) {
        nextResponder.becomeFirstResponder()
    } else {
        self.view.endEditing(true)
    }

}

func previousPressed(sender : UIBarButtonItem) {
    if let previousResponder = getPreviousResponderFor(tag : sender.tag)  {
        previousResponder.becomeFirstResponder()
    }
}

func getNextResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag + 1) as? UITextField
}

func getPreviousResponderFor(tag : Int) -> UITextField? {
    return self.view.viewWithTag(tag - 1) as? UITextField
}

Sie müssen die textFields-Tags in der Reihenfolge angeben, in der die Schaltfläche next/prev antworten soll. 

3
Mohammad Sadiq

Ohne Usings-Tags und ohne Hinzufügen einer Eigenschaft für nextField/nextTextField können Sie Folgendes versuchen, TAB zu emulieren, wobei "testInput" Ihr aktuelles aktives Feld ist:

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
Cœur

in textFieldShouldReturn sollten Sie überprüfen, ob das Textfeld, in dem Sie sich gerade befinden, nicht das letzte ist, wenn Sie auf Weiter klicken und die Tastatur nicht entfernt wird.

2
Daniel

Ich verwende die Antwort von Michael G. Emmons seit etwa einem Jahr und funktioniert hervorragend. Ich habe kürzlich festgestellt, dass der Aufruf von resignFirstResponder und dann von comeFirstResponder sofort dazu führen kann, dass die Tastatur "stört", verschwindet und dann sofort erscheint. Ich habe seine Version leicht geändert, um den resignFirstResponder zu überspringen, wenn nextField verfügbar ist.

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

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

 } 
 sonst{
 [textField resignFirstResponder]; 
 } 
 } 
 sonst{
 [textField resignFirstResponder]; 
 } 

 Rückgabe wahr; 

} 
2
arinmorf

Hier ist eine Swift 3-Version von Anth0 's Antwort. Ich poste es hier, um allen Swift-Entwicklern zu helfen, seine großartige Antwort zu nutzen! Ich habe mir die Freiheit genommen, einen Rückgabetyp "Weiter" hinzuzufügen, wenn Sie das zugehörige Objekt festlegen.

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

Hier ist eine weitere Erweiterung, die eine Möglichkeit zeigt, den obigen Code zum Durchlaufen einer Liste von UITextFields zu verwenden.

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

    next.becomeFirstResponder()
    return false
  }
}

Und dann in Ihrem ViewController oder wo auch immer, Sie können Ihre Textfelder so einrichten ...

@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
Justin Wright

Dies ist ein alter Beitrag, hat aber einen hohen Seitenrang, also werde ich mit meiner Lösung einrasten.

Ich hatte ein ähnliches Problem und erstellte eine Unterklasse von UIToolbar, um die nächste/vorherige/erledigte Funktionalität in einer dynamischen tableView mit Abschnitten zu verwalten: https://github.com/jday001/DataEntryToolbar

Sie legen die Symbolleiste als inputAccessoryView Ihrer Textfelder fest und fügen sie ihrem Wörterbuch hinzu. Auf diese Weise können Sie auch bei dynamischen Inhalten vorwärts und rückwärts durchlaufen. Es gibt Delegat-Methoden, wenn Sie Ihre eigene Funktionalität auslösen möchten, wenn die textField-Navigation stattfindet. Sie müssen sich jedoch nicht mit der Verwaltung von Tags oder dem Status der Ersthelfer beschäftigen.

Es gibt Code-Snippets und eine Beispiel-App am GitHub-Link, die Sie bei den Implementierungsdetails unterstützen. Sie benötigen ein eigenes Datenmodell, um die Werte in den Feldern zu verfolgen.

2
jday

sie können dazu die IQKeyboardManager-Bibliothek verwenden. Es erledigt alles, Sie benötigen keine zusätzlichen Einstellungen. IQKeyboardManager ist über CocoaPods verfügbar. Zur Installation fügen Sie einfach die folgende Zeile in Ihre Pod-Datei ein:

pod 'IQKeyboardManager'

oder Ziehen Sie einfach das IQKeyBoardManager-Verzeichnis aus dem Demoprojekt in Ihr Projekt. Das ist es ... Sie finden das IQKeyBoardManager-Verzeichnis unter https://github.com/hackiftekhar/IQKeyboardManager

2

Ein sicherer und direkter Weg, vorausgesetzt:

  • die Textfeld-Delegaten werden auf Ihren View-Controller festgelegt
  • alle Textfelder sind Unteransichten derselben Ansicht
  • die Textfelder enthalten Tags in der Reihenfolge, in der Sie fortfahren möchten (z. B. textField2.tag = 2, textField3.tag = 3 usw.).
  • sie können zum nächsten Textfeld wechseln, wenn Sie auf die Taste return tippen (Sie können dies in next, done usw.) ändern
  • sie möchten, dass die Tastatur nach dem letzten Textfeld geschlossen wird

Swift 4.1:

extension ViewController: UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        let nextTag = textField.tag + 1
        guard let nextTextField = textField.superview?.viewWithTag(nextTag) else {
            textField.resignFirstResponder()
            return false
        }

    nextTextField.becomeFirstResponder()

    return false

    }
}
1
jason z

Swift 3 Solution , mit geordnetem Array von UITextField's

func nextTextField() {
    let textFields = // Your textfields array

    for i in 0 ..< textFields.count{
        if let textfield = textFields[i], textfield.isFirstResponder{
            textfield.resignFirstResponder()
            if i+1 < textFields.count, let nextextfield = textFields[i+1]{
                nextextfield.becomeFirstResponder()
                return
            }
        }
    }
}
0
Maor