I have a table view that utilizes custom cells with UITextViews. Whenever a user is editing the text in a cell's textView and then hits return, a new cell is inserted to the list of data that populates the table view cells, and tableView.reloadData() is called so that the new cell shows up immediately. The textView.tag + 1 of the cell that was being edited when the user pressed return is stored as a variable called cellCreatedWithReturn, and if that variable is not nil when tableView is reloaded, the cell with that indexPath.row (so the new cell that was just created) becomes the first responder.
The issue I'm having is that when I hit return, the new cell is created and it is assigned as first responder, but the keyboard spazzes out because it starts to go into hiding and then shoots back up, instead of just staying put. An app that demonstrates the functionality I'm looking for would be Apple's Reminders app. When you hit return, a new cell is created and editing begins on that new cell, but the keyboard stays up the whole time without spazzing.
One thing I tried was commenting out the textView.endEditing(true) from my shouldChangeTextIn function to see if that was the cause of the keyboard being lowered, but this resulted in no change.
Here are my shouldChangeTextIn and cellForRowAt functions:
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()
}
}
}
}
First, handle your text view actions inside your cell class. Then use closures to tell the controller what has happened.
So, when the user taps Return:
shouldChangeTextIn
.performBatchUpdates()
to insert a cell at the next row in your table view.becomeFirstResponder()
Here's a very simple example: