使用“下一步”作为返回键

我使用“返回键”的“下一步”值来获取下一步button来代替完成button,但(显然)按下它不会自动移动到我的看法中的下一个UITextField。

什么是正确的方法来做到这一点? 我看到了很多答案,但任何人都有一个快速的解决scheme?

确保你的文本字段有他们的委托设置和实现textFieldShouldReturn方法。 这是用户点击返回键时调用的方法(不pipe它是什么样的)。

该方法可能看起来像这样:

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

这里的实际逻辑可能会有所不同。 有很多方法,如果你有很多的文本字段,我肯定会build议大量的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 } 

一旦你这样做,它应该只是一个问题,在viewDidLoad中设置每个文本字段的新的nextField属性:

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

虽然如果我们真的想要,我们可以用@IBOutlet它的前缀,这样可以让我们在界面构build器中连接我们的“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) } } } 

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

在这里输入图像说明

(当你在这里的时候,设置你的委托。)


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

这是Swift中的一个例子:

我用6个UITextField创build了一个屏幕。 我在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. } } 

其他答案没有什么不对,这只是一个不同的方法,而更关注于OOP – imho(尽pipe前面有更多的工作可以重用)。 在故事板中,我开始添加具有不同范围(例如800-810)的标签,这些标签定义了我想要在其间移动的字段的特定顺序。 这有利于跨主视图中的所有子视图,以便可以根据需要在UITextField和UITextView(以及任何其他控件)之间导航。

通常 – 我通常尝试在视图和自定义事件处理程序对象之间有视图控制器消息。 所以我使用从自定义的委托类传回给视图控制器的消息(aka,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) } .... } 

只是另一种方法来实现我发现有帮助的结果。 我的应用程序有11个文本字段,然后是文本视图。 我需要能够使用下一个键循环遍历所有字段,然后在textview之后退出键盘(即其他注释)。

在故事板中,我将标签设置为从1到12,12都是textview的所有字段(text和textview)。

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

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

 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 }