【问题标题】:How to prevent the keyboard from lowering when a new UITextView is assigned as first responder将新的 UITextView 分配为第一响应者时如何防止键盘降低
【发布时间】:2021-01-24 02:09:59
【问题描述】:

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

我遇到的问题是,当我按回车键时,会创建新单元格并将其分配为第一响应者,但键盘会因为它开始隐藏然后重新弹起,而不仅仅是留在原地。演示我正在寻找的功能的应用程序是 Apple 的提醒应用程序。当您按回车键时,会创建一个新单元格并在该新单元格上开始编辑,但键盘始终保持打开状态而不会发出声音。

我尝试的一件事是从我的 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()
                }
            }
        }

}

【问题讨论】:

    标签: ios swift uitableview textview first-responder


    【解决方案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
        }
        
    }
    

    【讨论】:

    • 再次感谢!回调就是答案:)
    • @michaelthedeveloper - 为了其他可能遇到您问题的人的利益...如果这解决了您的问题,请务必将答案标记为“已接受”
    猜你喜欢
    • 1970-01-01
    • 2011-05-29
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    相关资源
    最近更新 更多