Подтвердить что ты не робот

Использование "Следующий" в качестве возвращаемого ключа

Я использую значение "Next" для "Return Key", чтобы получить кнопку "Далее" вместо кнопки "Готово", но (очевидно) нажатие на нее не переключается автоматически на следующий UITextField в моем представлении.

Какой правильный способ сделать это? Я видел много ответов, но у кого есть быстрое решение?

4b9b3361

Ответ 1

Убедитесь, что ваши текстовые поля имеют свой набор делегатов и реализуют метод textFieldShouldReturn. Это метод, который вызывается, когда пользователь удаляет ключ возврата (независимо от того, как он выглядит).

Метод может выглядеть примерно так:

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

    return true
}

Действительная логика здесь может различаться. Существует множество подходов, и я бы определенно советовал против массивной цепочки if/else, если у вас много текстовых полей, но суть здесь заключается в том, чтобы определить, какое представление в настоящее время активно, чтобы определить, какой вид должен стать активный. После того, как вы определили, какое представление должно стать активным, вызовите этот метод просмотра becomeFirstResponder.


Для некоторой чистоты кода вы можете рассмотреть расширение UITextField, которое выглядит примерно так:

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

И затем измените наш метод textFieldShouldReturn, чтобы он выглядел следующим образом:

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

Как только вы это сделаете, нужно просто установить новое текстовое поле в качестве свойства nextField в viewDidLoad:

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

Хотя, если мы действительно хотели, мы могли бы префикс свойства с помощью @IBOutlet, и это позволило бы нам подключить наше свойство nextField прямо в конструкторе интерфейса.

Измените расширение так, чтобы оно выглядело следующим образом:

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

И теперь подключите свойство nextField в построителе интерфейса:

enter image description here

(Настройте свой делегат, пока вы здесь тоже.)


И, конечно, если свойство nextField возвращает nil, клавиатура просто скрывается.

Ответ 2

Вот пример в Swift:

Я создал экран с 6 UITextField s. Я назначил им теги с 1 по 6 в Interface Builder. Я также изменил ключ Return на Next в IB. Затем я выполнил следующие действия:

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

Ответ 3

Нет ничего плохого в других ответах, это просто другой подход с выгодой для того, чтобы быть более сосредоточенным на ООП-имхо (хотя это немного больше работы впереди, его можно использовать повторно). В раскадровке я начинаю добавлять теги с определенным диапазоном (например, 800-810), которые определяют конкретный порядок полей, которые я хочу переместить между ними. Это полезно для работы во всех подзонах в главном представлении, так что при необходимости можно перемещаться между UITextField и UITextView (и любым другим элементом управления).

Как правило, я обычно пытаюсь получить сообщение диспетчера представлений между представлениями и настраиваемыми объектами обработчика событий. Поэтому я использую сообщение (ака, NSNotification), переданное обратно контроллеру представления из пользовательского класса делегата.

(Обработчик делегатов TextField)

Примечание. В приложении AppDelegate.swift: 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
    }
}

Это позволяет моему контроллеру просмотра оставаться сосредоточенным на этом основном задании обработки обмена сообщениями между объектами, моделью и представлением.

(View Controller получает сообщение от делегата и передает инструкции, используя функцию advanceToNextField)

Примечание. В моей раскадровке мои классы пользовательского обработчика определяются с помощью NSObject, и этот объект связан с раскадрой как делегат для элементов управления, которые мне нужно отслеживать. Это приводит к автоматическому инициализации класса пользовательского обработчика.

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

    ....
}

Ответ 4

Еще один способ добиться результата, который я нашел полезным. В моем приложении было 11 текстовых полей, а затем текстовое представление. Мне нужно было прокручивать все поля с помощью следующего ключа, а затем сбрасывать клавиатуру после текстового просмотра (т.е. Другие заметки).

В раскадровке я устанавливаю тег во всех полях (как текстовом, так и текстовом), начиная с 1 по 12, 12 - текстового.

Я уверен, что есть другие способы сделать это, и этот метод не идеален, но, надеюсь, это помогает кому-то.

В коде я написал следующее:

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
}