当将新的UITextView分配为第一响应者时,如何防止键盘下降

时间:2020-10-09 00:49:27

标签: ios swift uitableview textview first-responder

我有一个表视图,该表视图使用带有UITextViews的自定义单元格。每当用户在单元格的textView中编辑文本然后点击回车时,都会将新的单元格插入到填充表格视图单元格的数据列表中,并调用tableView.reloadData()以便立即显示新单元格。用户按下回车键时正在编辑的单元格的textView.tag + 1存储为名为cellCreatedWithReturn的变量,如果重新加载tableView时该变量不为nil,则使用该indexPath.row的单元格(因此,新单元格刚刚创建的)成为第一响应者。

我遇到的问题是,当我按下回车键时,会创建新的单元格并将其分配为第一响应者,但是键盘会闪闪发光,因为它开始藏起来然后又向上射击,而不是仅仅保持原状。可以证明我正在寻找的功能的应用程序将是Apple的Reminders应用程序。当您按回车键时,将创建一个新单元格,并在该新单元格上开始编辑,但是键盘会一直保持启动状态,而不会出现闪烁现象。

我尝试做的一件事是从我的shouldChangeTextIn函数中注释掉textView.endEditing(true),看看这是否是降低键盘的原因,但这并没有导致更改。

这是我的shouldChangeTextIn和cellForRowAt函数:

var cellCreatedWithReturn: Int?

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if(text == "\n") {
            textView.endEditing(true)
            cellCreatedWithReturn = textView.tag + 1
            if song.lyrics.count == textView.tag || song.lyrics[textView.tag].text != "" {
                let newLyricLine = LyricLine()
                newLyricLine.text = ""
                do {
                    try realm.write {
                        self.song.lyrics.insert(newLyricLine, at: textView.tag)
                        print("Successfully inserted new lyric line in Realm")
                    }
                } catch {
                    print("Error when inserting new lyric line after pressing return")
                }
            }
            tableView.reloadData()
            return false
        } else {
            return true
        }
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "lyricsCell", for: indexPath) as! newNoteTableViewCell
        
        cell.lyricsField.delegate = self
        
        DispatchQueue.main.async {
            if let newCellIndexPath = self.cellCreatedWithReturn {
                if indexPath.row == newCellIndexPath {
                    cell.lyricsField.becomeFirstResponder()
                }
            }
        }

}

1 个答案:

答案 0 :(得分:1)

首先,在您的单元格类中 内部 处理您的文本视图操作。然后使用闭包告诉控制器发生了什么事。

因此,当用户点击Return时:

  • shouldChangeTextIn中拦截它
  • 使用闭包通知控制器
  • 在您的控制器中,向数据结构添加一个元素
  • 使用.performBatchUpdates()在表格视图的下一行插入一个单元格
  • 完成后,将新单元格中的文本视图告知.becomeFirstResponder()

这是一个非常简单的示例:

// simple cell with a text view
class TextViewCell: UITableViewCell, UITextViewDelegate {
    
    var textView = UITextView()
    
    // closure to tell controller Return was tapped
    var returnKeyCallback: (()->())?
    
    // closure to tell controller text was changed (edited)
    var changedCallback: ((String)->())?
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        textView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(textView)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            
            textView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            textView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            textView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            
            // use lessThanOrEqualTo for bottom anchor to prevent auto-layout complaints
            textView.bottomAnchor.constraint(lessThanOrEqualTo: g.bottomAnchor, constant: 0.0),
            
            textView.heightAnchor.constraint(equalToConstant: 60.0),

        ])
        
        textView.delegate = self
        
        // so we can see the text view frame
        textView.backgroundColor = .yellow
    }
    
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if(text == "\n") {
            returnKeyCallback?()
            return false
        }
        return true
    }
    func textViewDidChange(_ textView: UITextView) {
        let t = textView.text ?? ""
        changedCallback?(t)
    }
        
}

class AnExampleTableViewController: UITableViewController {
    
    // start with one "row" of string data
    var theData: [String] = [ "First row" ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(TextViewCell.self, forCellReuseIdentifier: "TextViewCell")
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return theData.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let c = tableView.dequeueReusableCell(withIdentifier: "TextViewCell", for: indexPath) as! TextViewCell
        
        c.textView.text = theData[indexPath.row]
        
        // handle Return key in text view in cell
        c.returnKeyCallback = { [weak self] in
            if let self = self {
                let newRow = indexPath.row + 1
                self.theData.insert("", at: newRow)
                let newIndexPath = IndexPath(row: newRow, section: 0)
                self.tableView.performBatchUpdates({
                    self.tableView.insertRows(at: [newIndexPath], with: .automatic)
                }, completion: { b in
                    guard let c = tableView.cellForRow(at: newIndexPath) as? TextViewCell else { return }
                    c.textView.becomeFirstResponder()
                })
            }
        }
        
        // update data whenever text in cell is changed (edited)
        c.changedCallback = { [weak self] str in
            if let self = self {
                self.theData[indexPath.row] = str
            }
        }
        
        return c
    }
    
}