如何根据具有打字机效果的UILabel设置单元格的高度

我在UITableView的单元格中有一个UILabel。

要根据标签的高度来调整单元格的高度,没关系,它可以很好地工作。

但是我需要添加另一个约束。 我需要用打字机效果(逐字母)显示UILabel。

我的扩展效果很好:

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 } } 

我试图在我的configureCell基金中调用这个函数:

 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) } 

但标签不出现。 我认为这是因为单元格中标签的高度设置为0,并且从不更新。

我不知道如何调整“实时”单元的高度(每次显示一个字符)

编辑

我使用自动布局

编辑2

打字机效果,运行在一个简单的UILabel没有UITableView:

GIF

在xib中设置的单元格:

厦门国际银行

当我运行时,UILabel不会出现:

跑

我能够实现使用不同的方法。

  • 我创build了一个堆栈视图来分组标签和button(和一个子堆栈视图排列你的button)。
  • 在button的堆栈视图中,我通过IB固定了高度。
  • 在父堆栈视图上。 我把堆栈视图固定到单元格的边缘。
  • 在标签上,我固定两边,以适应堆栈视图(不要钉在底部的一面,你可以自由钉住顶部)

这是我的IB屏幕截图作为参考。

  • 在您的ViewController上,设置以下属性:

     yourTableView.rowHeight = UITableViewAutomaticDimension yourTableView.rowHeight.estimatedRowHeight = 40 // You should set an initial estimated row height here, the number 40 was chosen arbitrarily 
  • 我编辑你的方法来添加一个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 } } 
  • 通过callback,在每次更新字符后,我beginUpdates()从TableView中endUpdates() beginUpdates()endUpdates()

希望以任何方式帮助你。

我find了一个解决scheme,但我不知道它是否非常干净。

我在configureCell方法中添加了layoutIfNeeded():

 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) 

}

我在我的控制器中添加了heightForRowAtIndexPath方法,它返回我的标签的高度:

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = tableView.dequeueReusableCell(withIdentifier: "ParagraphTableViewCell") as! ParagraphTableViewCell return cell.dialogueLabel.frame.height } 

它的工作原理,但我不明白为什么,因为在heightForRowAtIndexPath我返回标签的高度,而不是单元格的高度。

如果有人有更好的解决scheme,我很感兴趣。

你这样做的方式需要一点重构:你需要在你的TypeWriter函数中引用tableView。 无论如何,一个快速和肮脏的修复如下:

首先在你的单元格中添加一个对tableView的弱引用:

 class ParagraphTableViewCell: UITableViewCell { weak var tableView: UITableView? [...] } 

然后你去你的主循环寻找它,告诉tableView你正在更新的东西:

 DispatchQueue.main.async { if let delegate = (self.superview?.superview as? ParagraphTableViewCell)?.tableView { delegate.beginUpdates() self.text = self.text! + String(character) delegate.endUpdates() } } 

我不会build议在应用程序中使用这种方法,并且您肯定希望将其重构为更稳定的模式,我的示例显示了它如何与您的代码一起工作。

我已经创build了一个可用的示例来testing我的代码,请在此处将其打包