在Swift中,按下回车键切换文本字段

75

我正在设计一个iOS应用程序,当在我的iPhone上按下回车键时,我希望它将我指向下一个文本字段。

我找到了一些类似的问题,并且有很好的答案,但它们都是Objective-C代码,我正在寻找Swift代码,目前我有以下代码:

func textFieldShouldReturn(emaillabel: UITextField) -> Bool{
    return true
}

它被放置在与包含文本字段的UIView相连接和控制的文件中,但我不确定那是否是正确的位置。

好的,所以我尝试了这个并得到了这个错误:
//could not find an overload for '!=' that accepts the supplied arguments

func textFieldShouldReturn(textField: UITextField) -> Bool {
    let nextTag: NSInteger = textField.tag + 1
    // Try to find next responder
    let nextResponder: UIResponder = textField.superview!.viewWithTag(nextTag)!
    if (nextResponder != nil) {
        // could not find an overload for '!=' that accepts the supplied arguments

        // Found next responder, so set it.
        nextResponder.becomeFirstResponder()
    } else {
        // Not found, so remove keyboard.
        textField.resignFirstResponder()
    }
    return false // We do not want UITextField to insert line-breaks.
}

在最后一个UITextField中输入完毕后,是否可以切换到第一个UITextField? - Tirna
17个回答

163

确保你的 UITextField 代理已经设置并且标签被适当地增加。这也可以通过Interface Builder完成。

这是一个我找到的Obj-C帖子链接:如何浏览文本字段(下一步/完成按钮)

class ViewController: UIViewController,UITextFieldDelegate {
   // Link each UITextField (Not necessary if delegate and tag are set in Interface Builder)
   @IBOutlet weak var someTextField: UITextField!

   override func viewDidLoad() {
      super.viewDidLoad()
      // Do the next two lines for each UITextField here or in the Interface Builder
      someTextField.delegate = self
      someTextField.tag = 0 //Increment accordingly
   }

   func textFieldShouldReturn(_ textField: UITextField) -> Bool {
      // Try to find next responder
      if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {
         nextField.becomeFirstResponder()
      } else {
         // Not found, so remove keyboard.
         textField.resignFirstResponder()
      }
      // Do not add a line break
      return false
   }
}

1
通过“它们”,我假设你指的是委托。最简单的方法是通过IB来完成。进入你的Storyboard->点击每个UITextField->将委托拖到黄色的ViewController图标上。如果你指的是标签,那么你也可以通过IB来完成。点击每个UITextField,并从0开始递增设置标签。你也可以在ViewControllers的viewDidLoad中以编程方式设置委托和标签,通过设置textField.delegate = self和textField.tag = n。 - Caleb
请发帖报错信息。我进行了编辑,并将UIResponder更改为UIResponder! - Caleb
我添加了一个示例项目的链接。随意查看并告诉我是否解决了问题。顺便说一下:我通过IB设置了委托和标签。 - Caleb
当最后一个文本字段被输入并按回车键时,应用程序会崩溃,并显示“在解包可选值时意外发现nil”的错误信息。 - lucas rodriguez
2
@meteorSD 用文本字段数组?我不确定哪种做法比另一种更好。如果主要依赖界面生成器,标签似乎是最简单的方法。 - Caleb
显示剩余8条评论

44

Swift 5

当在键盘中点击返回键时, 您可以轻松切换到另一个TextField。

  • 首先, 您的视图控制器符合UITextFieldDelegate, 并在ViewController中添加textFieldShouldReturn(_:)委托方法
  • Interface Builder中从TextField拖动到ViewController。然后选择delegate选项。注意: 对于所有TextField都要这样做
  • 为所有TextFields创建IBOutlet

class ViewController: UIViewController, UITextFieldDelegate {

  @IBOutlet weak var txtFieldName: UITextField!
  @IBOutlet weak var txtFieldEmail: UITextField!
  @IBOutlet weak var txtFieldPassword: UITextField!

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if textField == txtFieldName {
       textField.resignFirstResponder()
       txtFieldEmail.becomeFirstResponder()
    } else if textField == txtFieldEmail {
       textField.resignFirstResponder()
       txtFieldPassword.becomeFirstResponder()
    } else if textField == txtFieldPassword {
       textField.resignFirstResponder()
    }
   return true
  }
}

2
工作得很好。但是如果需要调用becomeFirstResponder(),最好避免使用resignFirstResponder()这一行,因为当键盘出现和消失时,我的应用程序会出现某些抖动。 - Abdul Saleem

19

我建议你在textFieldShouldReturn(_:)方法中使用switch语句。

// MARK: UITextFieldDelegate

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    switch textField {
    case nameTextField:
        phoneTextField.becomeFirstResponder()
    case phoneTextField:
        emailTextField.becomeFirstResponder()
    case emailTextField:
        descriptionTextField.becomeFirstResponder()
    default:
        textField.resignFirstResponder()
    }
    return false
}

同意,更喜欢处理大小写! - Chris Peragine

9
这种方法需要对表视图和集合视图进行一些更改,但对于简单的表单来说应该没问题。
将您的textFields连接到一个IBOutletCollection,按其y坐标排序,并在textFieldShouldReturn(_ :)中直接跳转到下一个文本字段,直到到达结尾。
@IBOutlet var textFields: [UITextField]!

...

textFields.sortInPlace { $0.frame.origin.y < $1.frame.origin.y }

...

func textFieldShouldReturn(textField: UITextField) -> Bool {
    if let currentIndex = textFields.indexOf(textField) where currentIndex < textFields.count-1 {
        textFields[currentIndex+1].becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return true
}    

或者查看示例项目(xcode 7 beta 4)。


我不太确定我理解坐标部分,请您能否解释一下? - lucas rodriguez
1
当然。你想从顶部跳到最底部。因此,您可以按数组中的y坐标进行排序,因此在array [0]中是顶部的一个,在其下方的是array [1],而array [last]是底部的一个。这样足够了吗? - libec
排序是必要的,因为文本字段不能保证在出口集合中有序:https://medium.com/@abhimuralidharan/what-is-an-iboutletcollection-in-ios-78cfbc4080a1 - agirault

6

Swift & 编程

class MyViewController: UIViewController, UITextFieldDelegate {

    let textFieldA = UITextField()
    let textFieldB = UITextField()
    let textFieldC = UITextField()
    let textFieldD = UITextField()

    var textFields: [UITextField] {
        return [textFieldA, textFieldB, textFieldC, textFieldD]
    }

    override func viewDidLoad() {
        // layout textfields somewhere 
        // then set delegate
        textFields.forEach { $0.delegate = self }
    }

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if let selectedTextFieldIndex = textFields.firstIndex(of: textField), selectedTextFieldIndex < textFields.count - 1 {
            textFields[selectedTextFieldIndex + 1].becomeFirstResponder()
        } else {
            textField.resignFirstResponder() // last textfield, dismiss keyboard directly
        }
        return true
    }
}

1
最佳解决方案(比使用标签被接受的方案更Swifty)-完美运作! - 10623169

5

CalebSwift 4.0中的版本

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    if let nextField = self.view.viewWithTag(textField.tag + 1) as? UITextField {
        nextField.becomeFirstResponder()
    } else {
        textField.resignFirstResponder()
    }
    return false
}

附注:对我来说textField.superview?无法工作


4

我尝试了许多代码,最终在 Swift 3.0 最新版 [2017年3月] 中找到了可行的方法。

"ViewController" 类应该继承 "UITextFieldDelegate" 才能让这段代码正常工作。

class ViewController: UIViewController,UITextFieldDelegate  

添加带有正确标记编号的文本字段,该标记编号用于根据分配给它的增量标记编号将控件传递到适当的文本字段。

override func viewDidLoad() {

 userNameTextField.delegate = self

        userNameTextField.tag = 0

        userNameTextField.returnKeyType = UIReturnKeyType.next

        passwordTextField.delegate = self

        passwordTextField.tag = 1


        passwordTextField.returnKeyType = UIReturnKeyType.go

}

在上面的代码中,“returnKeyType = UIReturnKeyType.next”将使键盘返回键显示为“下一个”,您还可以根据应用程序更改值,例如“加入/前往”等其他选项。
“textFieldShouldReturn”是UITextFieldDelegate控制的方法,在这里我们基于标签值的递增进行下一个字段选择。
func textFieldShouldReturn(_ textField: UITextField) -> Bool

    {

        if let nextField = textField.superview?.viewWithTag(textField.tag + 1) as? UITextField {

            nextField.becomeFirstResponder()

        } else {

            textField.resignFirstResponder()

            return true;

        }

        return false

    }

3

最简单的切换到下一个文本框的方法是这样的,无需编写冗长的代码。

override func viewDidLoad() {
        super.viewDidLoad()

        emailTextField.delegate = self
        passwordTextField.delegate = self
    }


    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField == emailTextField {
            passwordTextField.becomeFirstResponder()
        }else {
            passwordTextField.resignFirstResponder()
        }
            return true
    }

3
我有一个关于你问题的好解决方案。
步骤:
1 - 从故事板中设置你的返回键。

enter image description here

2 - 在您的 Swift 文件中。

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if textField.returnKeyType == .next {
            Email.resignFirstResponder()
            Password.becomeFirstResponder()
        } else if textField.returnKeyType == .go {
            Password.resignFirstResponder()
            self.Login_Action()
        }
        return true
    }

3 - 不要忘记设置文本框的委托。

谢谢 :)


1
谢谢你的回答。这正是我在寻找的。对于那些新手可能会在第3点关于委托上迷失方向的人,可以通过将你的类扩展为UITextFieldDelegate(你可以查看本问题中的任何其他答案来理解)来解决。然后在viewDidLoad中添加yourTextFieldName.delegate = self。 - Jiraheta

2

Swift 4+这段代码会对你有所帮助。

class YOURClass: UITextFieldDelegate {
  override func viewDidLoad() {

    //delegate your textfield in here
     choosenTextField1.delegate = self
     choosenTextField2.delegate = self

    }

  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        switch textField.tag {
          case 1:
            choosenTextField1.becomeFirstResponder()
          case 2:
            choosenTextField2.becomeFirstResponder()
          default:
            break   
        }
        
        return true
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接