如何根据具有打字机效果的 UILabel 设置单元格的高度
How to set the height of a cell depending on a UILabel with a typewriter effect
我在 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,并且从未更新过。
不知道如何调整单元格的高度"in live"(每次显示一个字符)
编辑
我使用自动布局
编辑 2
打字机效果,运行 在没有 UITableView 的简单 UILabel 中:
xib中的单元格集合:
当我运行时,UILabel没有出现:
我找到了一个解决方案,但我不知道它是否是一个非常干净的解决方案。
我在 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 方法,returns 我的标签的高度:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCell(withIdentifier: "ParagraphTableViewCell") as! ParagraphTableViewCell
return cell.dialogueLabel.frame.height
}
它有效,但我不明白为什么,因为在 heightForRowAtIndexPath 中我返回标签的高度而不是单元格的高度。
如果有人有更好的解决方案,我很感兴趣。
我能够使用不同的方法实现。
- 我创建了一个堆栈视图来对标签和按钮进行分组(以及一个子堆栈视图来排列您的按钮)。
- 在按钮的堆栈视图上,我通过 IB 固定了高度。
- 在父堆栈视图中。我将堆栈视图固定到单元格的边距。
- 在标签上,我固定了两侧以适合堆栈视图(不要固定底部,您可以自由固定顶部)
这是我的 IB Screen Shot 以供参考。
在您的 ViewController 上,设置以下属性:
yourTableView.rowHeight = UITableViewAutomaticDimension
yourTableView.rowHeight.estimatedRowHeight = 40 // You should set an initial estimated row height here, the number 40 was chosen arbitrarily
我编辑了你的方法以添加回调。
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
}
}
并且通过回调,我在每次字符更新后从 TableView 调用了 beginUpdates()
和 endUpdates()
。
希望这对您有所帮助。
您执行此操作的方式需要进行一些重构:您需要在 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()
}
}
我不建议在应用程序中采用这种方法,并且您肯定希望将其重构为更可靠的模式,我的示例展示了它如何与您的代码一起使用。
我创建了一个工作示例来测试我的代码,git它here
我在 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,并且从未更新过。
不知道如何调整单元格的高度"in live"(每次显示一个字符)
编辑
我使用自动布局
编辑 2
打字机效果,运行 在没有 UITableView 的简单 UILabel 中:
xib中的单元格集合:
当我运行时,UILabel没有出现:
我找到了一个解决方案,但我不知道它是否是一个非常干净的解决方案。
我在 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 方法,returns 我的标签的高度:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let cell = tableView.dequeueReusableCell(withIdentifier: "ParagraphTableViewCell") as! ParagraphTableViewCell
return cell.dialogueLabel.frame.height
}
它有效,但我不明白为什么,因为在 heightForRowAtIndexPath 中我返回标签的高度而不是单元格的高度。
如果有人有更好的解决方案,我很感兴趣。
我能够使用不同的方法实现。
- 我创建了一个堆栈视图来对标签和按钮进行分组(以及一个子堆栈视图来排列您的按钮)。
- 在按钮的堆栈视图上,我通过 IB 固定了高度。
- 在父堆栈视图中。我将堆栈视图固定到单元格的边距。
- 在标签上,我固定了两侧以适合堆栈视图(不要固定底部,您可以自由固定顶部)
这是我的 IB Screen Shot 以供参考。
在您的 ViewController 上,设置以下属性:
yourTableView.rowHeight = UITableViewAutomaticDimension yourTableView.rowHeight.estimatedRowHeight = 40 // You should set an initial estimated row height here, the number 40 was chosen arbitrarily
我编辑了你的方法以添加回调。
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 } }
并且通过回调,我在每次字符更新后从 TableView 调用了
beginUpdates()
和endUpdates()
。
希望这对您有所帮助。
您执行此操作的方式需要进行一些重构:您需要在 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()
}
}
我不建议在应用程序中采用这种方法,并且您肯定希望将其重构为更可靠的模式,我的示例展示了它如何与您的代码一起使用。
我创建了一个工作示例来测试我的代码,git它here