在 Swift 中按 return 键在文本字段之间切换

Switching between Text fields on pressing return key in Swift

我正在设计一个 iOS 应用程序,我希望当在我的 iPhone 中按下 return 键时,它会将我引导至下一个文本字段。

我发现了几个类似的问题,周围都有很好的答案,但它们恰好都在 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.
}

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

if self.emaillabel.isEqual(self.anotherTextField)
{
    self.anotherTextField.becomeFirstResponder()
}

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

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

这是一个 link 到 Obj-C post 我发现: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
   }
}

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

将您的 textFields 连接到一个 IBOutletCollection,按其 y 坐标对其进行排序,然后在 textFieldShouldReturn(_:) 中跳转到下一个文本字段,直到到达终点:

@IBOutlet var textFields: [UITextField]!

...

textFields.sortInPlace { [=10=].frame.origin.y < .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)

我尝试了很多代码,最后在 Swift 3.0 最新版 [2017 年 3 月]

中对我有用

"ViewController" class 应该继承 "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" 将使小键盘 return 键显示为 "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

    }

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

  1. 为 link Cell 和 TableViewController 创建一个新协议。

    protocol CellResponder {
      func setNextResponder(_ fromCell: UITableViewCell)
    }
    
  2. 将协议添加到您的单元格,其中您的 TextField 委托也是单元格(我在 Storyboard 中这样做)。

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

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

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
    }

Swift 5

单击键盘上的 return 键可以轻松切换到另一个 TextField。

  • 首先,您的视图控制器符合UITextFieldDelegate并在ViewController
  • 中添加textFieldShouldReturn(_:)委托方法
  • TextField 拖到 Interface Builder 中的 ViewController。然后 select 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
      }
    }
    

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

没什么特别的,这是我目前用来更改文本文件的。所以 ViewController 中的代码看起来不错 :)。 #斯威夫特4

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

Caleb 的 版本 Swift 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
}

P.S。 textField.superview? 不适合我

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

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

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

步骤:

1 - 从情节提要中设置您的 return 键。

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 - 不要忘记设置文本字段的委托。

谢谢:)

Swift 4.2

这是一个更通用和最简单的解决方案,您可以将此代码与任意数量的文本字段一起使用。 只需继承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
}

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 { [=10=].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
    }
}

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

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

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

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
}

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

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

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 { [=10=].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
    }
}