511 Stimmen

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

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

Das letzte Textfeld sollte die Tastatur schließen.

Ich habe die IB the Buttons (Next / Done) eingerichtet, aber jetzt komme ich nicht weiter.

Ich habe die Aktion textFieldShouldReturn implementiert, aber jetzt schließen die Schaltflächen Next und Done die Tastatur.

593voto

PeyloW Punkte 36534

In Cocoa für Mac OS X gibt es die Next-Responder-Kette, mit der Sie das Textfeld fragen können, welches Steuerelement als nächstes den Fokus erhalten soll. Auf diese Weise funktioniert das Tabbing zwischen Textfeldern. Aber da iOS-Geräte keine Tastatur haben, nur Touch, hat dieses Konzept nicht den Übergang zu Cocoa Touch überlebt.

Dies lässt sich jedoch leicht bewerkstelligen, wenn man zwei Annahmen trifft:

  1. Alle "tabulierbar" UITextField s in der gleichen übergeordneten Ansicht befinden.
  2. Ihre "Tabulator-Reihenfolge" wird durch die Tag-Eigenschaft definiert.

Unter dieser Voraussetzung können Sie 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 etwas mehr 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 die Superansicht des Textfeldes eine UITableViewCell ist, dann ist der nächste Responder

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

172voto

memmons Punkte 39772

Hay una viel eine elegantere Lösung, die mich schon beim ersten Mal umgehauen hat. Vorteile:

  • Näher an der OSX-Textfeld-Implementierung, bei der ein Textfeld weiß, wohin der Fokus als nächstes gehen soll
  • Verlässt sich nicht auf das Setzen oder Verwenden von Tags, die IMO für diesen Anwendungsfall anfällig sind.
  • Kann erweitert werden, um mit beiden zu arbeiten UITextField y UITextView Steuerelemente - oder jedes UI-Steuerelement für die Tastatureingabe
  • Überfrachtet den View-Controller nicht mehr mit UITextField-Delegate-Code (Kesselstein)
  • Lässt sich gut in IB integrieren und kann über die bekannte Option "Drag-Drop" konfiguriert werden, um Ausgänge zu verbinden.

Erstellen Sie eine UITextField-Unterklasse, die eine IBOutlet Eigenschaft namens nextField. Hier ist die Überschrift:

@interface SOTextField : UITextField

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

@end

Und hier ist die Umsetzung:

@implementation SOTextField

@end

In Ihrem View-Controller erstellen Sie die -textFieldShouldReturn: Methode delegieren:

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

In IB ändern Sie Ihre UITextFields, um die SOTextField Klasse. Als nächstes setzen Sie, ebenfalls in IB, den Delegaten für jedes der "SOTextFields" auf "File's Owner" (genau dort, wo Sie den Code für die Delegatenmethode - textFieldShouldReturn - platzieren). Das Schöne an diesem Entwurf ist, dass Sie jetzt einfach mit der rechten Maustaste auf ein beliebiges textField klicken und den nextField-Ausgang dem nächsten SOTextField Objekt, auf das Sie als nächstes antworten möchten.

Assigning nextField in IB

Außerdem können Sie coole Sachen machen, wie z.B. die textFields in eine Schleife legen, so dass, nachdem das letzte den Fokus verloren hat, das erste wieder den Fokus erhält.

Dies kann leicht erweitert werden, um automatisch die returnKeyType de la SOTextField zu einer UIReturnKeyNext wenn ein nextField zugewiesen ist - eine Sache weniger, die manuell konfiguriert werden muss.

92voto

mxcl Punkte 25282

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

Arbeiten mit dem (meist unbekannten) UIControlEventEditingDidEndOnExit UITextField Aktion.

Sie können dies auch leicht im Storyboard einbinden, also keine Delegation oder Code erforderlich ist.

Bearbeiten: Eigentlich kann ich nicht herausfinden, wie man dies in Storyboard einhaken. becomeFirstResponder scheint keine angebotene Aktion für dieses Kontroll-Ereignis zu sein, was schade ist. Dennoch können Sie alle Ihre Textfelder mit einer einzigen Aktion in Ihrem ViewController verknüpfen, die dann bestimmt, welches TextFeld zu becomeFirstResponder basierend auf dem Absender (obwohl es dann nicht so elegant ist wie die obige programmatische Lösung, so dass es IMO mit dem obigen Code in viewDidLoad ).

78voto

Anth0 Punkte 2944

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 etwas zu tun), habe ich beschlossen, eine benutzerdefinierte Eigenschaft zum UITextField-Objekt hinzuzufügen. Mit anderen Worten habe ich eine Kategorie auf UITextField wie folgt 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

Und so verwende 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 Methode textFieldShouldReturn :

- (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, jeder weiß, wer der nächste in der Reihe ist.

Ich hoffe, es hilft Ihnen.

50voto

Amos Joshua Punkte 1416

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 die Eingabetaste für alle Felder bis auf das letzte auf "Weiter" und für das letzte Feld auf "Fertig" und verschiebt den Fokus bzw. schließt die Tastatur, wenn sie angetippt wird.

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: so verwenden -

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X