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

我正在设计一个 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

标签: ios swift uitextfielddelegate


【解决方案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】:

          斯威夫特 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 委托成为单元格以保持组件分离或单向的纯粹主义者的另一种方法...

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

            protocol CellResponder {
              func setNextResponder(_ fromCell: UITableViewCell)
            }
            
          2. 将协议添加到您的单元格,您的 TextField 代表也是单元格(我在情节提要中执行此操作)。

            class MyTableViewCell: UITableViewCell, UITextFieldDelegate {
              var responder: CellResponder?
            
              func textFieldShouldReturn(_ textField: UITextField) -> Bool {
                responder?.setNextResponder(self)
                return true
              }
            }
            
          3. 使您的 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
                        }
                    }
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-07-31
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多