I have a UILabel in a cell of UITableView.
To adjust the height of the cell depending the height of the label, it's ok, it works perfectly.
But I need to add another constraints. I need to display the UILabel with a typewriter effect (letter by letter).
My extension for the effect works well:
extension UILabel{
func setTextWithTypeAnimation(id:String, typedText: String, pauseCharacterArray: [Int:Double], characterInterval: TimeInterval = 0.06 ) {
text = ""
let group = DispatchGroup()
group.enter()
DispatchQueue.global(qos: .userInteractive).async {
for (index, character) in typedText.characters.enumerated() {
DispatchQueue.main.async {
self.text = self.text! + String(character)
}
Thread.sleep(forTimeInterval: characterInterval)
}
group.leave()
}
group.notify(queue: .main) {
//do something
}
}
I tried to call this function in my configureCell fund :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ParagraphTableViewCell", for: indexPath) as! ParagraphTableViewCell
cell.delegate = self
self.configureCell(cell: cell, atIndexPath: indexPath)
return cell
}
func configureCell(cell: ParagraphTableViewCell, atIndexPath indexPath: IndexPath) {
let paragraph = paragraphArray[indexPath.row] as! Paragraph
let pauseCharactersArray:[Int:Double] = [1:0, 6:0]
cell.dialogueLabel.setTextWithTypeAnimation(id:"intro", typedText: "lorem ipsum", pauseCharacterArray: pauseCharactersArray)
}
But the label doesn't appear. I think it's because the height of the label in the cell is set to 0, and it's never updated.
I don't know how to adjust the height of the cell "in live" (every time a character is displayed)
EDIT
I use autolayout
EDIT 2
The typewriter effect, run in a simple UILabel without UITableView:
The cell set in the xib:
When I run, the UILabel doesn't appear:
I was able to achieve using a different method.
Here is my IB Screen Shot to use as reference.
On your ViewController, set the following properties:
yourTableView.rowHeight = UITableViewAutomaticDimension
yourTableView.rowHeight.estimatedRowHeight = 40 // You should set an initial estimated row height here, the number 40 was chosen arbitrarily
I edited your method to add an callback.
func setTextWithTypeAnimation(id:String, typedText: String, pauseCharacterArray: [Int:Double], characterInterval: TimeInterval = 0.06, callBackAfterCharacterInsertion:(()->())?) {
text = ""
let group = DispatchGroup()
group.enter()
DispatchQueue.global(qos: .userInteractive).async {
for (_, character) in typedText.characters.enumerated() {
DispatchQueue.main.async {
self.text = self.text! + String(character)
callBackAfterCharacterInsertion?()
}
Thread.sleep(forTimeInterval: characterInterval)
}
group.leave()
}
group.notify(queue: .main) {
//do something
}
}
And through the callback, I called the beginUpdates()
and endUpdates()
, from the TableView, after each character update.
Hope this help you in any way.
I found a solution but I don't know if it's a very clean one.
I added layoutIfNeeded() in configureCell method :
func configureCell(cell: ParagraphTableViewCell, atIndexPath indexPath: IndexPath) {
let paragraph = paragraphArray[indexPath.row] as! Paragraph
cell.layoutIfNeeded()
let pauseCharactersArray:[Int:Double] = [1:0, 6:0]
cell.dialogueLabel.setTextWithTypeAnimation(id:"intro", typedText: "lorem ipsum", pauseCharacterArray: pauseCharactersArray)
}
And I added the heightForRowAtIndexPath method in my controller, which returns the height of my label:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCell(withIdentifier: "ParagraphTableViewCell") as! ParagraphTableViewCell
return cell.dialogueLabel.frame.height
}
It works, but I don't understand exactly why, because in heightForRowAtIndexPath I'm returning the height of the label and not the height of the cell.
If someone has a better solution, I'm interested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With