成为FirstResponder 和多个 UITextField 焦点

Posted

技术标签:

【中文标题】成为FirstResponder 和多个 UITextField 焦点【英文标题】:BecomeFirstResponder and Multiple UITextField Focus 【发布时间】:2018-03-20 18:01:47 【问题描述】:

所以我有一个视图 -> UITextField 和 UILabel 是两个孩子,我有多个包含孩子的视图。 我正在使用下面的委托函数,并将每个 UITextfields 分配为委托“textFieldShouldReturn(_ textField: UITextField) -> Bool”。但是,当我按下回车键时,它们似乎并没有改变 textField 焦点。将这种焦点技术与 UITextFields 一起使用时,无需将它们嵌套在视图中。它让我可以毫无问题地改变焦点。为什么在视图中嵌套 UITextField 会导致下一个 UITextField 无法成为第一响应者?我已经阅读了一些关于第一个响应程序及其工作原理的内容,但它并没有清楚地解释如何解决这个问题。

class ScrollingViewWithFields:UIViewController, UITextFieldDelegate 

let scrollView = UIScrollView()
let contentView = UIView()

var textFields:[UITextField] = []
var labeledTextField:[LabeledTextField] = []

override func viewDidLoad() 
    contentView.backgroundColor = UIColor.white
    contentView.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(scrollView)
    scrollView.addSubview(contentView)

    scrollView.translatesAutoresizingMaskIntoConstraints = false
    scrollView.backgroundColor = UIColor.white
    let top = view.safeAreaLayoutGuide.topAnchor
    let bottom = view.safeAreaLayoutGuide.bottomAnchor

    NSLayoutConstraint.activate([
        scrollView.topAnchor.constraint(equalTo: top),
        scrollView.bottomAnchor.constraint(equalTo: bottom),
        scrollView.leftAnchor.constraint(equalTo: view.leftAnchor),
        scrollView.rightAnchor.constraint(equalTo: view.rightAnchor)
    ])



    let ltf = LabeledTextField()
    ltf.translatesAutoresizingMaskIntoConstraints = false

    contentView.addSubview(ltf)
    ltf.populate(title: "Hello", font: UIFont.systemFont(ofSize: 14.0))
    ltf.textField.delegate = self
    ltf.textField.tag = 0
    let ltf2 = LabeledTextField()
    ltf2.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(ltf2)
    ltf2.populate(title: "What", font: UIFont.systemFont(ofSize: 14.0))
    ltf2.textField.tag = 1
    ltf2.textField.delegate = self



    self.textFields.append(ltf2.textField)
    self.textFields.append(ltf.textField)

    NSLayoutConstraint.activate([
        ltf.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0),
        ltf.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
        ltf.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 8.0),
        ltf.heightAnchor.constraint(equalToConstant: 60)
    ])

    NSLayoutConstraint.activate([
        ltf2.topAnchor.constraint(equalTo: ltf.bottomAnchor, constant: 8.0),
        ltf2.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
        ltf2.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: 8.0),
        ltf2.heightAnchor.constraint(equalToConstant: 60)
        ])

    NSLayoutConstraint.activate([
        contentView.topAnchor.constraint(equalTo: scrollView.topAnchor),
        contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
        contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
        contentView.heightAnchor.constraint(equalToConstant:4000)
    ])



func textFieldShouldReturn(_ textField: UITextField) -> Bool 

    let tag = textField.tag
    let next = tag + 1

    if next < self.textFields.count 
        let textField = self.textFields[next]

        textField.becomeFirstResponder()
        self.scrollView.contentOffset = CGPoint(x: 0.0, y: textField.frame.origin.y - 8.0)

     else 
        textField.resignFirstResponder()
    

    return true

【问题讨论】:

【参考方案1】:

问题在于您在文本字段上设置标签并将它们放入数组中的方式。

ltf.textField.tag = 0
ltf2.textField.tag = 1

self.textFields.append(ltf2.textField)
self.textFields.append(ltf.textField)

标签与数组中的顺序不匹配的问题,因为数组最终会是[ltf2.textField, ltf.textField]。我会完全跳过使用标签,只使用数组中的顺序。

func textFieldShouldReturn(_ textField: UITextField) -> Bool 
    if let index = textFields.index(of: textField) 
        let nextIndex = index + 1
        let lastIndex = textFields.count - 1

        if nextIndex <= lastIndex 
            textFields[nextIndex].becomeFirstResponder()
        
    
    return true

【讨论】:

【参考方案2】:

您可以保留内存而不是声明一个数组来隐藏文本字段并尝试这样的操作

func textFieldShouldReturn(_ textField: UITextField) -> Bool

    if let next =  self.view.viewWithTag(textField.tag + 1) as? UITextField
                
        next.becomeFirstResponder()
             
    else
    
        textField.resignFirstResponder()
    
    return true


【讨论】:

以上是关于成为FirstResponder 和多个 UITextField 焦点的主要内容,如果未能解决你的问题,请参考以下文章

inputAccessoryView 中的 UITextField 不会成为FirstResponder

UINavigationItem.titleView 能否成为FirstResponder?

检测插入的单元格,然后让它成为FirstResponder

当 UITextField 成为FirstResponder 时得到通知

UIColletionViewCell 内的 UITextField 成为FirstResponder

非 View 类可以成为 FirstResponder 吗?