ios 使用“Next”作为回车键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27028617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:41:50  来源:igfitidea点击:

Using "Next" as a Return Key

iosswiftuitextfield

提问by Octavio Antonio Cede?o

I use the "Next" value for the "Return Key" to get the Next button in place of the Done button, but (obviously) pressing it doesn't automatically move to the next UITextField in my view.

我使用“Return Key”的“Next”值来获取“Next”按钮代替“Done”按钮,但是(显然)按下它不会自动移动到我视图中的下一个 UITextField 。

What's the right way to do this? I have seen many answers, but anyone have a swift solution?

这样做的正确方法是什么?我看过很多答案,但有人有快速的解决方案吗?

回答by nhgrif

Make sure your text fields have their delegate set and implement the textFieldShouldReturnmethod. This is the method that is called when the user taps the return key (no matter what it looks like).

确保您的文本字段设置了它们的委托并实现了该textFieldShouldReturn方法。这是在用户点击返回键时调用的方法(不管它看起来像什么)。

The method might look something like this:

该方法可能如下所示:

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

    return true
}

The actual logic in here might vary. There are numerous approaches, and I'd definitely advise against a massive if/elsechain if you have lots of text fields, but the gist here is to determine what view is currently active in order to determine what view should become active. Once you've determined which view should become active, call that view's becomeFirstRespondermethod.

这里的实际逻辑可能会有所不同。有很多方法,如果您有很多文本字段,我肯定会建议不要使用大规模if/else链,但这里的要点是确定当前处于活动状态的视图,以便确定应激活的视图。一旦确定哪个视图应该变为活动状态,调用该视图的becomeFirstResponder方法。



For some code cleanliness, you might consider a UITextFieldextension that looks something like this:

对于某些代码清洁度,您可能会考虑一个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)
        }
    }
}

And then change our textFieldShouldReturnmethod to look like this:

然后将我们的textFieldShouldReturn方法更改为如下所示:

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

Once you've done this, it should simply be a matter of setting each text field's new nextFieldproperty in viewDidLoad:

完成此操作后,只需在 中设置每个文本字段的新nextField属性即可viewDidLoad

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


Although if we really wanted, we could prefix the property with @IBOutlet, and that would allow us to hook up our "nextField" property right in interface builder.

虽然如果我们真的想要,我们可以用 前缀属性@IBOutlet,这将允许我们在界面构建器中连接我们的“nextField”属性。

Change the extension to look like this:

将扩展名更改为如下所示:

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

And now hook up the nextFieldproperty in interface builder:

现在nextField在界面构建器中连接属性:

enter image description here

在此处输入图片说明

(Set up your delegate while you're here too.)

(在您也在这里时设置您的代表。)



And of course, if the nextFieldproperty returns nil, the keyboard just hides.

当然,如果nextField属性返回nil,键盘就会隐藏。

回答by vacawama

Here is an example in Swift:

这是 Swift 中的一个示例:

I created a screen with 6 UITextFields. I assigned them the tags 1 through 6 in Interface Builder. I also changed the Return key to Next in IB. Then I implemented the following:

我创建了一个 6UITextField秒的屏幕。我在 Interface Builder 中为它们分配了标签 1 到 6。我还在 IB 中将 Return 键更改为 Next。然后我实现了以下内容:

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

回答by Tommie C.

There is nothing wrong with the other answers, this is just a different approach with the benefit of being more focused on OOP - imho (although this is a bit more work up front, it can be reused). In the storyboard, I start off adding tags with a distinct range (e.g 800-810) that define the specific order of the fields I want to move between. This has the benefit of working across all subviews in the main view so that one can navigate between UITextField's and UITextView's (and any other control) as needed.

其他答案没有任何问题,这只是一种不同的方法,其好处是更专注于 OOP - imho(虽然这需要更多的工作,但可以重用)。在故事板中,我开始添加具有不同范围(例如 800-810)的标签,这些标签定义了我想要在它们之间移动的字段的特定顺序。这样做的好处是可以跨主视图中的所有子视图工作,以便可以根据需要在 UITextField 和 UITextView(以及任何其他控件)之间导航。

Generally - I typically try to have view controllers message between views and custom event handler objects. So I use a message (aka, NSNotification) passed back to the view controller from a custom delegate class.

通常 - 我通常尝试在视图和自定义事件处理程序对象之间使用视图控制器消息。所以我使用从自定义委托类传递回视图控制器的消息(又名 NSNotification)。

(TextField Delegate Handler)

(TextField 委托处理程序)

Note: In AppDelegate.swift: let defaultCenter = NSNotificationCenter.defaultCenter()

注意:在 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
    }
}

This allows my view controller to remain focused on it's main job of handling the messaging between objects, model and view.

这使我的视图控制器可以专注于处理对象、模型和视图之间的消息传递的主要工作。

(View Controller receives a message from the delegate and passes instructions using the advanceToNextField function)

(视图控制器接收来自委托的消息并使用 AdvanceToNextField 函数传递指令)

Note: In my storyboard my custom handler classes are defined using an NSObject and that object is linked into the storyboard as a delegate for the controls that I need monitored. Which causes the custom handler class to be initialized automatically.

注意:在我的故事板中,我的自定义处理程序类是使用 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)
    }

    ....
}

回答by sarac

Just another way to achieve the result that I found helpful. My app had 11 text fields followed by a text view. I needed to be able to cycle through all fields using the next key and then resign the keyboard following the textview (i.e. other notes).

这是实现我认为有用的结果的另一种方法。我的应用程序有 11 个文本字段,后跟一个文本视图。我需要能够使用下一个键循环浏览所有字段,然后在文本视图(即其他注释)之后退出键盘。

In the storyboard, I set the tag on all of the fields (both text and textview) starting with 1 through 12, 12 being the textview.

在故事板中,我在从 1 到 12 开始的所有字段(文本和文本视图)上设置标签,12 是文本视图。

I'm sure there are other ways to do it and this method isn't perfect, but hopefully it helps someone.

我确信还有其他方法可以做到这一点,这种方法并不完美,但希望它可以帮助某人。

In code, I wrote the following:

在代码中,我写了以下内容:

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
}