在 Swift 中按下返回键时在文本字段之间切换

Posted

技术标签:

【中文标题】在 Swift 中按下返回键时在文本字段之间切换【英文标题】:Switching between Text fields on pressing return key in Swift 【发布时间】:2015-08-01 22:39:35 【问题描述】:

我正在设计一个 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 【参考方案1】:

确保您的UITextField 代表已设置并且标签已正确递增。这也可以通过 Interface Builder 完成。

这是我找到的 Obj-C 帖子的链接:How to navigate through textfields (Next / Done Buttons)

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
   

【讨论】:

我将如何设置它们,我对此很陌生,老实说现在很迷茫 “他们”是指代表。最简单的方法是通过 IB 做到这一点。转到您的故事板->单击每个 UITextField->将委托拖到黄色的 ViewController 图标上。如果您指的是标签,那么您也可以通过 IB 执行此操作。单击每个 UITextField 并设置从 0 开始并以 1 递增的标签。您还可以通过设置 textField.delegate = self 和 textField.tag = n 在 ViewControllers viewDidLoad 中以编程方式设置委托和标签 请发布错误。我进行了编辑并将 UIResponder 更改为 UIResponder! 我添加了一个示例项目的链接。随意看看,如果你解决了,请告诉我。仅供参考:我通过 IB 设置代表和标签。 @meteorSD 有一组文本字段?我不确定这两种做法是否比另一种更好。当主要依赖于 Interface Builder 时,标签似乎是最简单的方法。【参考方案2】:

斯威夫特 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
  

【讨论】:

工作得很好。但是,如果调用 becomeFirstResponder() 时避免使用 resignFirstResponder() 行会很好,因为我的应用程序在键盘移动和返回时会显示一些抽搐。【参考方案3】:

我建议你应该在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

【讨论】:

同意,优先办案!【参考方案4】:

这种方法需要对表视图和集合视图进行一些更改,但我猜对于简单的表单来说还可以。

将您的 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
    

或者只看sample project(xcode 7 beta 4)

【讨论】:

我不太确定我理解坐标部分,你能解释一下吗? 当然。你想从最上面的那个跳到最下面的那个。因此,您按数组中的 y 坐标对其进行排序,因此 array[0] 是顶部的一个,array[1] 是它下面的一个,array[last] 是底部的一个。够了吗? 排序是必要的,因为不能保证文本字段在插座集合中排序:medium.com/@abhimuralidharan/…【参考方案5】:

我尝试了很多代码,最后在 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”将使键盘返回键显示为“Next”,您还可以选择其他选项,如“Join/Go”等,根据您的应用程序更改值.

这个“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

    

【讨论】:

【参考方案6】:

Swift 4.0

中的Caleb版本
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? 不适合我

【讨论】:

【参考方案7】:

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
    

【讨论】:

最佳解决方案(比使用标签的公认解决方案更快捷)-完美运行!【参考方案8】:

更改为下一个文本字段的最简单方法是无需长代码

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
    

【讨论】:

【参考方案9】:

我对你的问题有一个很好的解决方案。

步骤:

1 - 从情节提要中设置返回键。

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 - 不要忘记设置 Textfield 的委托。

谢谢你:)

【讨论】:

感谢您的回答。这就是我一直在寻找的。对于那些新的并且可能在关于代表的第 3 点上迷失的人。使用 UITextFieldDelegate 扩展您的课程(您可以查看此问题中的任何其他答案以供您理解)。然后在 viewDidLoad 添加 yourTextFieldName.delegate = self.【参考方案10】:

只需在 textFieldShouldReturn 方法中使用 UIResponder 类的 becomeFirstResponder() 方法即可。每个UIView 对象都是UIResponder 的子类。

if self.emaillabel.isEqual(self.anotherTextField)

    self.anotherTextField.becomeFirstResponder()

您可以在 Apple Doc 的 here 中找到有关 becomeFirstResponder() 方法的更多信息。

【讨论】:

【参考方案11】:

Swift 4.2

这是一个更通用和最简单的解决方案,您可以将此代码与任意数量的 TextField 一起使用。 只需继承UITextFieldDelegate并按照顺序更新Textfield Tag并复制此函数

func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    let txtTag:Int = textField.tag

    if let textFieldNxt = self.view.viewWithTag(txtTag+1) as? UITextField 
        textFieldNxt.becomeFirstResponder()
    else
        textField.resignFirstResponder()
    

    return true

【讨论】:

以上不适用于 SwiftUI。 textFieldNxt 总是不断评估 nil【参考方案12】:

对于不喜欢使用标签并希望 UITextField 委托成为单元格以保持组件分离或单向的纯粹主义者的另一种方法...

    创建一个新协议来链接 Cell 和 TableViewController。

    protocol CellResponder 
      func setNextResponder(_ fromCell: UITableViewCell)
    
    

    将协议添加到您的单元格,其中您的 TextField 代表也是单元格(我在情节提要中执行此操作)。

    class MyTableViewCell: UITableViewCell, UITextFieldDelegate 
      var responder: CellResponder?
    
      func textFieldShouldReturn(_ textField: UITextField) -> Bool 
        responder?.setNextResponder(self)
        return true
      
    
    

    使您的 TableViewController 符合 CellResponder 协议(即class MyTableViewController: UITableViewController, CellResponder)并按照您的意愿实现该方法。 IE。如果你有不同的单元格类型,那么你可以这样做,同样你可以传入 IndexPath,使用标签等。不要忘记在 cellForRow 中设置cell.responder = self..

    func setNextResponder(_ fromCell: UITableViewCell) 
      if fromCell is MyTableViewCell, let nextCell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? MySecondTableViewCell 
    
        nextCell.aTextField?.becomeFirstResponder()
    
       ....
    
    

【讨论】:

【参考方案13】:

没有什么特别的,这是我目前用来更改textFiled的。所以 ViewController 中的代码看起来不错:)。 #Swift4

final class SomeTextFiled: UITextField 

  public var actionKeyboardReturn: (() -> ())?

  override init(frame: CGRect) 
      super.init(frame: frame)
      super.delegate = self
  

  required init?(coder aDecoder: NSCoder) 
      super.init(coder: aDecoder)
      fatalError("init(coder:) has not been implemented")
  

  func textFieldShouldReturn(_ textField: UITextField) -> Bool 
      self.resignFirstResponder()
      actionKeyboardReturn?()
      return true
   


extension SomeTextFiled: UITextFieldDelegate 


class MyViewController : UIViewController 

    var tfName: SomeTextFiled!
    var tfEmail: SomeTextFiled!
    var tfPassword: SomeTextFiled!

    override func viewDidLoad() 
        super.viewDidLoad()
        tfName = SomeTextFiled(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        tfName.actionKeyboardReturn =  [weak self] in
            self?.tfEmail.becomeFirstResponder()
        
        tfEmail = SomeTextFiled(frame: CGRect(x: 100, y: 0, width: 100, height: 100))
        tfEmail.actionKeyboardReturn =  [weak self] in
            self?.tfPassword.becomeFirstResponder()
        
        tfPassword = SomeTextFiled(frame: CGRect(x: 200, y: 0, width: 100, height: 100))
        tfPassword.actionKeyboardReturn = 
            /// Do some further code
        
    

【讨论】:

【参考方案14】:

如果您有很多文本字段组件,最好使用插座集合,链接文本字段并从界面构建器设置返回键

@IBOutlet var formTextFields: [UITextField]!

override func viewDidLoad() 
  for textField in formTextFields 
    textField.delegate = self
  


extension RegisterViewController: UITextFieldDelegate 
  func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    if let componentIndex = formTextFields.firstIndex(of: textField) 
      if textField.returnKeyType == .next,
        componentIndex < (formTextFields.count - 1) 
        formTextFields[componentIndex + 1].becomeFirstResponder()
       else 
        textField.resignFirstResponder()
      
    
    return true
  

【讨论】:

【参考方案15】:

您可以使用字段标签。我认为这比其他更容易。

首先,您必须在此处输入代码,以便为您的字段添加标签。

在我的代码中,usernameField 标记为 0,passwordField 标记为 1。然后我检查了我的标记。然后做进程。

func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    if textField.tag == 0 
        passwordField.becomeFirstResponder()
     else if textField.tag == 1 
        self.view.endEditing(true)
        loginFunc()
     else 
        print("Hata var")

    
     return false

如果在用户名字段上单击返回,则输入密码。 或者如果您在密码字段时单击返回,请运行登录功能登录。

【讨论】:

【参考方案16】:

斯威夫特 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
  

【讨论】:

【参考方案17】:

viewWithTag 是一个糟糕的解决方案,因为超级视图可能有带有标签集的视图。这样更好:

public extension Collection where Element: Equatable 
    func element(after element: Element) -> Element? 
        guard let index = firstIndex(of: element) else  return nil 
        let nextIndex = self.index(after: index)
        return nextIndex < endIndex ? self[nextIndex] : nil
    


class Controller: UIViewController 

    @IBOutlet weak var firstNameTextField: UITextField!
    @IBOutlet weak var lastNameTextField: UITextField!
    @IBOutlet weak var companyTextField: UITextField!

    private lazy var primaryTextFields: [UITextField] = 
        [firstNameTextField, lastNameTextField, companyTextField]
    ()

    override func viewDidLoad() 
        super.viewDidLoad()
        primaryTextFields.forEach  $0.delegate = self 
    


extension Controller: UITextFieldDelegate 
    func textFieldShouldReturn(_ textField: UITextField) -> Bool 
        if let next = primaryTextFields.element(after: textField) 
            next.becomeFirstResponder()
         else if primaryTextFields.contains(textField) 
            textField.resignFirstResponder()
        
        return true
    

【讨论】:

以上是关于在 Swift 中按下返回键时在文本字段之间切换的主要内容,如果未能解决你的问题,请参考以下文章

按下返回按钮时在 UITextField 之间切换

按下返回键时如何在下一个 UITextField 上移动控件

在 VC6-MFC 中按 ENTER 键时的 TAB 效果

WPF:一个文本框,它具有在按下 Enter 键时触发的事件

在 PyQt5 中按下时如何切换按钮文本

在 Swift 中点击返回键时如何关闭 UIAlertController?