在Swift中按回车键可在文本字段之间切换


68

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

Answers:


151

确保UITextField已设置代表,并且标记已正确递增。这也可以通过界面生成器来完成。

这是我发现的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进行此操作。转到您的情节提要->单击每个UITextField->将委托拖到黄色的ViewController图标上。如果您的意思是标记,那么您也可以通过IB进行。单击每个UITextField,然后设置标记(从0开始,以1递增)。您还可以通过设置textField.delegate = self和textField.tag = n
Caleb

请张贴错误。我进行了编辑,并将UIResponder更改为UIResponder!
卡列布(Caleb)2015年

我将链接添加到示例项目。随意看一下,让我知道是否解决。仅供参考:我通过IB设置了代表和标签。
卡列布(Caleb)2015年

2
@meteorSD有文本字段数组吗?我不确定这两种做法是否比另一种更好。当主要依赖于Interface Builder时,标记似乎是最简单的方法。
卡雷布

40

迅捷5

单击键盘中的返回键时,可以轻松切换到另一个TextField。

  • 首先,您的视图控制器符合ViewControllerUITextFieldDelegatetextFieldShouldReturn(_:)ViewController中添加委托方法
  • 从拖动文本字段视图控制器Interface Builder中。然后选择delegate选项。注意:对所有TextField执行此操作
  • IBOutlet为所有TextField创建一个

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

1
做得好。但是,如果有对成为beginFirstResponder()的调用,则避免使用resignFirstResponder()行将是一件好事,因为当键盘前后移动时,我的应用程序显示出一些抖动。
塞卡

18

我建议您在中使用switch语句textFieldShouldReturn(_:)

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

同意,最好处理案件!
克里斯·佩拉吉娜

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

排序是必需的,因为不能保证在插座集合中对文本字段进行排序:medium.com/@abhimuralidharan/…–
agirault

4

我尝试了许多代码,最终在Swift 3.0 Latest [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控制的方法,在此我们基于Tag值的增量选择下一个字段

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

    }

4

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
}

PStextField.superview?不适用于我


4

快速和编程

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
最佳解决方案(比使用标签更快的解决方案)-完美地工作!
10623169 '19

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
    }

2

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

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

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


2

对于您的问题,我有一个很好的解决方案。

步:

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

在此处输入图片说明

2-在您的快速文件中。

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的委托。

谢谢 :)


2

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

1

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

  1. 创建一个新协议来链接单元格和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),并根据需要实现该方法。也就是说,如果您具有不同的单元格类型,则可以执行此操作,同样,您可以传递IndexPath,使用标签等。请不要忘记cell.responder = self在cellForRow中进行设置。

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

1

没什么特别的,这是我目前用来更改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
        }
    }
}

1

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

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

0

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

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

在我的代码上,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
}

如果单击返回用户名字段,请输入密码。或者,如果单击“密码返回时”字段,请运行登录功能进行登录。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.