【问题标题】:Issue in `becomeFirstResponder()` in swiftswift 中的 `becomeFirstResponder()` 中的问题
【发布时间】:2018-08-31 21:54:00
【问题描述】:

我有六个textfields。现在,如果我所有的textfield 都被填满并点击任何textfield,它应该始终将焦点放在第六个textfield 上并显示键盘。我尝试了下面的代码,但它没有显示keyboard,并且只有在我点击第六个textfield 时才聚焦。请告诉我这是什么问题?

func textFieldDidBeginEditing(_ textField: UITextField) {
     textField.inputAccessoryView = emptyView
        if let textOneLength = textFieldOne.text?.length ,let textTwoLength = textFieldTwo.text?.length ,let textThreeLength = textFieldThree.text?.length , let textFourLength = textFieldFour.text?.length,let textFiveLength = textFieldFive.text?.length , let textSixLength = textFieldSix.text?.length {
            if (textOneLength > 0) && (textTwoLength > 0) && (textThreeLength > 0) && (textFourLength > 0) && (textFiveLength > 0) && (textSixLength > 0) {
                self.textFieldSix.becomeFirstResponder()
            } else if (textOneLength <= 0) && (textTwoLength <= 0) && (textThreeLength <= 0) && (textFourLength <= 0) && (textFiveLength <= 0) && (textSixLength <= 0){
                self.textFieldOne.becomeFirstResponder()
            }
        }
}

【问题讨论】:

  • 我确信这是微不足道的。您是否调试过条件的执行方式?当您按下或不按下时,是否会调用 becomeFirstResponder?是否调用了委托方法本身?
  • 为所有文本字段设置委托
  • 代表被召唤。当我点击文本字段 6 时,它才起作用。
  • 调试并检查您的条件如何根据您的 if 语句工作
  • 检查 textFieldSix 是否有实例或其 nil

标签: ios swift keyboard uitextfield uitextfielddelegate


【解决方案1】:

我认为接受的答案是 hack。我们可以做的其他事情是在UITextField 上检测touchDown,检查最后一个textField 是否应该成为焦点并对其执行becomeFirstResponder()。接下来,如果 last 应该成为焦点,我们应该禁止关注其他 textFields。我们可以在textFieldShouldBeginEditing 方法中做到这一点。

这里是ViewController 的示例。只需连接 3 个文本字段,所有内容都应该按预期工作(Swift 4):

class ViewController: UIViewController {

    @IBOutlet weak var firstTextField: UITextField!
    @IBOutlet weak var secondTextField: UITextField!
    @IBOutlet weak var thirdTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        firstTextField.delegate = self
        secondTextField.delegate = self
        thirdTextField.delegate = self

        firstTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
        secondTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
        thirdTextField.addTarget(self, action: #selector(textFieldTouch(_:)), for: .touchDown)
    }

    @IBAction private func textFieldTouch(_ sender: UITextField) {
        if shouldFocusOnLastTextField {
            thirdTextField.becomeFirstResponder()
        }
    }

    private var shouldFocusOnLastTextField: Bool {
        return firstTextField.text?.isEmpty == false && secondTextField.text?.isEmpty == false  && thirdTextField.text?.isEmpty == false
    }

}

extension ViewController: UITextFieldDelegate {

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        guard shouldFocusOnLastTextField else { return true }
        return textField == thirdTextField
    }

}

其他更简单的方法来实现检查将要聚焦的文本字段:

extension ViewController: UITextFieldDelegate {

    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        guard firstTextField.text?.isEmpty == false &&
            secondTextField.text?.isEmpty == false  &&
            thirdTextField.text?.isEmpty == false &&
            textField != thirdTextField else { return true }

        thirdTextField.becomeFirstResponder()
        return false
    }

}

【讨论】:

  • 这会起作用,但是对于一件简单的事情来说工作量太大了
【解决方案2】:

您的实现的问题在于,您尝试分配已经分配给另一个文本字段的第一响应者。
以下代码应该可以解决问题:

extension TestViewController: UITextFieldDelegate {

func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.inputAccessoryView = UIView()
}

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    if let textOneLength = textFieldOne.text?.count ,let textTwoLength = textFieldTwo.text?.count ,let textThreeLength = textFieldThree.text?.count , let textFourLength = textFieldFour.text?.count,let textFiveLength = textFieldFive.text?.count , let textSixLength = textFieldSix.text?.count {
        if (textOneLength > 0) && (textTwoLength > 0) && (textThreeLength > 0) && (textFourLength > 0) && (textFiveLength > 0) && (textSixLength > 0) {

            ///Check if the sixth textField was selected to avoid infinite recursion
            if textFieldSix != textField {
                self.textFieldSix.becomeFirstResponder()
                return false

            }
        } else if (textOneLength <= 0) && (textTwoLength <= 0) && (textThreeLength <= 0) && (textFourLength <= 0) && (textFiveLength <= 0) && (textSixLength <= 0){

            ///Check if the first textField was selected to avoid infinite recursion
            if textFieldOne != textField {
                self.textFieldOne.becomeFirstResponder()
                return false
            }
        }
    }
    return true
}

}

【讨论】:

    【解决方案3】:

    应该可以了。您确定模拟器具有显示键盘启用的属性吗? 您可以使用以下键更改该属性:Command + Shift + k

    【讨论】:

    • 你确定: 1 - ViewController 实现 UITextFieldDelegate "class NAME: UIViewcontroller, UITextFieldDelegate" 2 - 所有文本字段都有一个委托 textFieldOne.delegate = self textFieldTwo.delegate = self textFieldThree.delegate = self textFieldFour.delegate = self textFieldFive.delegate = self textFieldSix.delegate = self
    • 你写的都在那里,但我不明白是什么问题
    • 拜托,告诉我你的swift版本是什么,我给你做个例子,我会发给你的。
    【解决方案4】:

    我知道这对我来说也很奇怪,但是延迟对文本字段的关注对我有用。

     DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                    self.textFieldOne.becomeFirstResponder()
                }
    

    我在 textFieldDidBeginEdting 中添加了上面的代码,它就像魔术一样工作。

    【讨论】:

    • 嗨,@Techiee。你的回答只是一个黑客。请看我的answer
    • 我认为 hack 节省了我很多时间,也让我免于编写大量代码。我知道我的方法不好。我会试试你的答案
    • 从技术上讲,将来您可以处理袋子甚至因为延迟而崩溃。再次,检查我的答案。它非常紧凑,应该可以工作;)
    • 您真的需要延迟吗?在这些情况下,我刚刚使用了 DispatchQueue.main.async()。对我来说,这是一种有效的方法,可以将焦点请求的更改延迟到 textFieldDidBeginEditing 完成之后,它本身正试图影响焦点
    【解决方案5】:

    在这种情况下,您需要在尝试编辑发生之前拒绝它们;当我们希望拒绝尝试的编辑时,我们还需要将第六个文本字段设置为新的第一响应者。

    extension MyViewController: UITextFieldDelegate {
      func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        if textFieldOne.text?.isEmpty == false && textFieldTwo.text?.isEmpty == false  && textFieldThree.text?.isEmpty == false && textFieldFour.text?.isEmpty == false && textFieldFive.text?.isEmpty == false && textFieldSix.text?.isEmpty == false  {
          if textField != textFieldSix {
            textFieldSix.becomeFirstResponder()
            return false
          } else {
            return true
          }
        } else {
          return true
        }
      }
    }
    

    【讨论】:

    • 您确定此代码有效吗?我做了一些关闭的事情并且发生了崩溃。
    【解决方案6】:

    1在viewcontroller中设置UITextfielddelegate

    2为每个文本字段设置自我委托

    3为每个文本字段添加标签值

    4添加textfield.becomeFirstResponder()

    5检查条件是否使用标签指定文本字段值

    【讨论】:

      【解决方案7】:

      参考这个答案https://stackoverflow.com/a/27098244/4990506

      只有当当前响应者对象成为第一个响应者时 响应者可以放弃第一响应者状态(canResignFirstResponder) 并且新的响应者可以成为第一响应者。

      您可以调用此方法来使响应者对象(例如视图)成为第一响应者。但是,您应该只在该视图上调用它,如果 它是视图层次结构的一部分。如果视图的 window 属性持有 UIWindow 对象,它已安装在视图层次结构中;如果它 返回 nil,视图与任何层次结构分离。

      首先将委托设置为所有字段

      self.textFieldOne.delegate = self
      self.textFieldTwo.delegate = self
      self.textFieldThree.delegate = self
      self.textFieldFour.delegate = self
      self.textFieldFive.delegate = self
      self.textFieldSix.delegate = self
      

      然后委托

      extension ViewController : UITextFieldDelegate{
          func textFieldDidBeginEditing(_ textField: UITextField) {
              if self.textFieldOne.hasText ,self.textFieldTwo.hasText ,self.textFieldThree.hasText ,self.textFieldFour.hasText ,self.textFieldFive.hasText ,self.textFieldSix.hasText  {
                  textFieldSix.perform(
                      #selector(becomeFirstResponder),
                      with: nil,
                      afterDelay: 0.1
                  )
              }else if !self.textFieldOne.hasText ,!self.textFieldTwo.hasText ,!self.textFieldThree.hasText ,!self.textFieldFour.hasText ,!self.textFieldFive.hasText ,!self.textFieldSix.hasText {
                  textFieldOne.perform(
                      #selector(becomeFirstResponder),
                      with: nil,
                      afterDelay: 0.1
                  )
              }
          }
      }
      

      【讨论】:

        【解决方案8】:

        要检查任何文本字段,请使用此代码

        for view in self.view.subviews {
            if let textField = view as? UITextField {
                print(textField.text!)
            }
        }
        

        ** 你也可以使用这个来识别一个文本文件 -

        if let txtFieldINeed = self.view.viewWithTag(99) as? UITextField {
            print(txtFieldINeed.text!)
        }
        

        ** 然后使用 -- txtFieldINeed.becomeFirstResponder()

        ** 确保开启此选项 -- * iOS 模拟器 -> 硬件 -> 键盘 * 取消勾选“连接硬件键盘”

        【讨论】:

          猜你喜欢
          • 2015-02-28
          • 2017-12-19
          • 2013-03-26
          • 2015-12-25
          • 2021-04-15
          • 2015-07-07
          • 2015-09-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多