it-swarm.com.de

Verwenden Sie "Weiter" als Return-Taste

Ich verwende den "Next" -Wert für die "Return-Taste", um die Next-Schaltfläche anstelle der Done-Schaltfläche zu erhalten, aber (offensichtlich) durch Drücken der Taste wird nicht automatisch das nächste UITextField-Element in meiner Ansicht angezeigt.

Was ist der richtige Weg, dies zu tun? Ich habe viele Antworten gesehen, aber hat jemand eine schnelle Lösung?

Stellen Sie sicher, dass für Ihre Textfelder ein Delegat festgelegt ist, und implementieren Sie die textFieldShouldReturn-Methode. Dies ist die Methode, die aufgerufen wird, wenn der Benutzer die Return-Taste antippt (egal wie er aussieht).

Die Methode könnte ungefähr so ​​aussehen:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    if textField == self.field1 {
        self.field2.becomeFirstResponder()
    }

    return true
}

Die tatsächliche Logik hier kann variieren. Es gibt zahlreiche Ansätze, und ich würde definitiv von einer massiven if/else-Kette abraten, wenn Sie viele Textfelder haben. Der Grundgedanke besteht jedoch darin, zu bestimmen, welche Ansicht derzeit aktiv ist, um zu bestimmen, welche Ansicht aktiv werden soll. Wenn Sie festgelegt haben, welche Ansicht aktiviert werden soll, rufen Sie die becomeFirstResponder-Methode dieser Ansicht auf.


Für etwas Code-Sauberkeit können Sie eine UITextField-Erweiterung in Betracht ziehen, die ungefähr so ​​aussieht:

private var kAssociationKeyNextField: UInt8 = 0

extension UITextField {
    var nextField: UITextField? {
        get {
            return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
        }
        set(newField) {
            objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
        }
    }
}

Und ändern Sie dann unsere textFieldShouldReturn-Methode so, dass sie folgendermaßen aussieht:

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.nextField?.becomeFirstResponder()
    return true
}

Wenn Sie dies getan haben, müssen Sie einfach die neue nextField-Eigenschaft jedes Textfelds in viewDidLoad festlegen:

self.field1.nextField = self.field2
self.field2.nextField = self.field3
self.field3.nextField = self.field4
self.field4.nextField = self.field1

Wenn wir es wirklich wollten, könnten wir der Eigenschaft @IBOutlet voranstellen, und dies würde uns erlauben, unser "nextField" -Eigenschaftsrecht im Interface-Builder anzuhängen.

Ändern Sie die Erweiterung folgendermaßen:

private var kAssociationKeyNextField: UInt8 = 0

extension UITextField {
    @IBOutlet var nextField: UITextField? {
        get {
            return objc_getAssociatedObject(self, &kAssociationKeyNextField) as? UITextField
        }
        set(newField) {
            objc_setAssociatedObject(self, &kAssociationKeyNextField, newField, .OBJC_ASSOCIATION_RETAIN)
        }
    }
}

Verbinden Sie nun die nextField-Eigenschaft im Interface-Builder:

enter image description here

(Richten Sie Ihren Delegierten ein, während Sie auch hier sind.)


Wenn die nextField-Eigenschaft nil zurückgibt, wird die Tastatur natürlich nur ausgeblendet.

82
nhgrif

Hier ist ein Beispiel in Swift:

Ich habe einen Bildschirm mit 6 UITextFields erstellt. Ich habe ihnen im Interface Builder die Tags 1 bis 6 zugewiesen. Ich habe auch die Return-Taste in IB in Next geändert. Dann habe ich folgendes umgesetzt:

import UIKit

// Make your ViewController a UITextFieldDelegate    
class ViewController: UIViewController, UITextFieldDelegate {

    // Use a dictionary to define text field order 1 goes to 2, 2 goes to 3, etc.
    let nextField = [1:2, 2:3, 3:4, 4:5, 5:6, 6:1]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // Make ourselves the delegate of the text fields so that textFieldShouldReturn
        // will be called when the user hits the Next/Return key
        for i in 1...6 {
            if let textField = self.view.viewWithTag(i) as? UITextField {
                textField.delegate = self
            }
        }
    }

    // This is called when the user hits the Next/Return key        
    func textFieldShouldReturn(textField: UITextField) -> Bool {
        // Consult our dictionary to find the next field
        if let nextTag = nextField[textField.tag] {
            if let nextResponder = textField.superview?.viewWithTag(nextTag) {
                // Have the next field become the first responder
                nextResponder.becomeFirstResponder()
            }
        }
        // Return false here to avoid Next/Return key doing anything
        return false
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}
8
vacawama

Es gibt nichts Falsches an den anderen Antworten, dies ist nur ein anderer Ansatz mit dem Vorteil einer stärkeren Konzentration auf OOP - imho (obwohl dies im Vorfeld etwas mehr Arbeit bedeutet, kann es wiederverwendet werden). Im Storyboard fange ich an, Tags mit einem bestimmten Bereich (z. B. 800-810) hinzuzufügen, die die spezifische Reihenfolge der Felder definieren, zwischen denen ich wechseln möchte. Dies hat den Vorteil, dass in der Hauptansicht über alle Unteransichten hinweg gearbeitet wird, sodass nach Bedarf zwischen UITextFields und UITextViews (und anderen Steuerelementen) navigiert werden kann. 

Allgemein - Ich versuche normalerweise, eine Ansichtssteuerungsnachricht zwischen Ansichten und benutzerdefinierten Ereignisbehandlungsobjekten zu haben. Daher verwende ich eine Nachricht (aka NSNotification), die von einer benutzerdefinierten Delegatklasse an den View-Controller zurückgegeben wurde.

(TextField-Delegatenhandler)

Hinweis: In AppDelegate.Swift: let defaultCenter = NSNotificationCenter.defaultCenter ()

//Globally scoped
struct MNGTextFieldEvents {
    static let NextButtonTappedForTextField = "MNGTextFieldHandler.NextButtonTappedForTextField"
}

class MNGTextFieldHandler: NSObject, UITextFieldDelegate {

    var fields:[UITextField]? = []

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        return true
    }
    func textFieldDidBeginEditing(textField: UITextField) {
        textField.backgroundColor = UIColor.yellowColor()
    }
    func textFieldDidEndEditing(textField: UITextField) {
        textField.backgroundColor = UIColor.whiteColor()
    }
    func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
        return true
    }
    func textFieldShouldClear(textField: UITextField) -> Bool {
        return false
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool {
        return true
    }
    func textFieldShouldReturn(textField: UITextField) -> Bool {

        //passes the message and the textField (with tag) calling the method
        defaultCenter.postNotification(NSNotification(name: MNGTextFieldEvents.NextButtonTappedForTextField, object: textField))

        return false
    }
}

Dadurch kann sich mein Ansichtscontroller auf seine Hauptaufgabe konzentrieren, die Nachrichten zwischen Objekten, Modellen und Ansichten zu verwalten.

(View Controller empfängt eine Nachricht vom Delegaten und übergibt Anweisungen mit der Funktion advanceToNextField.)

Hinweis: In meinem Storyboard werden meine benutzerdefinierten Handlerklassen mithilfe eines NSObject definiert. Dieses Objekt wird als Delegat für die Steuerelemente, die überwacht werden sollen, mit dem Storyboard verknüpft. Dadurch wird die benutzerdefinierte Handler-Klasse automatisch initialisiert.

class MyViewController: UIViewController {
    @IBOutlet weak var tagsField: UITextField! { didSet {
        (tagsField.delegate as? MNGTextFieldHandler)!.fields?.append(tagsField)
        }
    }
    @IBOutlet weak var titleField: UITextField!{ didSet {
        (titleField.delegate as? MNGTextFieldHandler)!.fields?.append(titleField)
        }
    }
    @IBOutlet weak var textView: UITextView! { didSet {
     (textView.delegate as? MNGTextViewHandler)!.fields?.append(textView)

        }
    }

    private struct Constants {
     static let SelectorAdvanceToNextField = Selector("advanceToNextField:")
}
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        registerEventObservers()
    }
    override func viewDidDisappear(animated: Bool) {
        super.viewDidDisappear(animated)
        deRegisterEventObservers()
    }

    func advanceToNextField(notification:NSNotification) {
        let currentTag = (notification.object as! UIView).tag

        for aView in self.view.subviews {
            if aView.tag == currentTag + 1 {
                aView.becomeFirstResponder()
            }
        }
    }

    func registerEventObservers () {

        defaultCenter.addObserver(self, selector: Constants.SelectorAdvanceToNextField, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
    }

    func deRegisterEventObservers() {

        defaultCenter.removeObserver(self, name: MNGTextFieldEvents.NextButtonTappedForTextField, object: nil)
    }

    ....
}
2
Tommie C.

Nur ein weiterer Weg, um das Ergebnis zu erreichen, das ich hilfreich fand. Meine App hatte 11 Textfelder, gefolgt von einer Textansicht. Ich musste in der Lage sein, alle Felder mit der nächsten Taste zu durchlaufen und dann die Tastatur nach der Textansicht neu auszurichten (d. H. Andere Noten).

Im Storyboard habe ich das Tag für alle Felder (sowohl Text als auch Textansicht) festgelegt, beginnend mit 1 bis 12, wobei 12 die Textansicht ist.

Ich bin sicher, dass es andere Möglichkeiten gibt, und dies ist nicht perfekt, aber hoffentlich hilft es jemandem.

Im Code habe ich folgendes geschrieben:

func textFieldShouldReturn(textField: UITextField) -> Bool {

    let nextTag = textField.tag + 1

    //Handle Textview transition, Textfield programmatically
    if textField.tag == 11 {
        //Current tag is 11, next field is a textview
        self.OtherNotes.becomeFirstResponder()

    } else if nextTag > 11 {
        //12 is the end, close keyboard
        textField.resignFirstResponder()

    } else {
        //Between 1 and 11 cycle through using next button
        let nextResponder = self.view.viewWithTag(nextTag) as? UITextField
        nextResponder?.becomeFirstResponder()

    }

    return false
}

func textFieldDidEndEditing(textField: UITextField) {

    textField.resignFirstResponder()
}

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    //Remove keyboard when clicking Done on keyboard
    if(text == "\n") {
        textView.resignFirstResponder()
        return false
    }
    return true
}
1
sarac