自定义 UITableview 单元格偶尔会在其他单元格之上重叠/复制 [英] Custom UITableview Cell Occasionally Overlapping/Reproducing On Top Of Other Cell
问题描述
我在这里遇到了非常奇怪的问题.
Really strange problem I'm having here.
基本上,用户来到一个附有 TableView 的视图.调用后端获取一些数据,并在该数据的完成块中提供给 TableView 以显示.
Basically, the user comes to a View that has a TableView attached to it. There's a call to the backend for some data, and in the completion block of that data is provided to the TableView to display.
在 cellForRow 1 of 4 可重用中,自定义单元格根据某种逻辑出列,然后调用该单元格的配置方法.
In cellForRow 1 of 4 reusable, custom cells is dequeued, based on some logic, and then a configure method for that cell is called.
这就是它变得棘手的地方:某些单元格可能需要进一步的异步调用(为其自定义显示获取更多数据),因此需要调用 tableView.reloadRows ......那么,这两个最好解释发生了什么截图:
Here's where it gets tricky: Some of the cells might require further asynchronous calls (to fetch more data for their custom displays), thus required a tableView.reloadRows call...What's happening, then, is best explained by these two screenshots:
在第一个单元格中,有没有想过你会为克朗代克酒吧做什么?"复制在演员的自我管理"单元格之上,因为包含 Twitter 信息的单元格需要额外的异步调用来获取该数据.
In the first one, that cell with "Ever wonder what YOU'D do for a klondike bar?" is replicated on top of the "Self-Management for Actor's" cell which, as a cell containing Twitter info DID require an additional asynch call to fetch that data.
有什么想法吗?我在 begin/endUpdates 块内运行 tableView.reloadRows 调用,但没有骰子.
Any thoughts? I'm running the tableView.reloadRows call inside of a begin/endUpdates block, but no dice.
cellForRow:
cellForRow:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let postAtIndexPath = posts[indexPath.row]
let cell: PostCell!
if postAtIndexPath.rawURL == "twitter.com" {
cell = tableView.dequeueReusableCell(withIdentifier: "TwitterCell", for: indexPath) as! TwitterCell
} else if !postAtIndexPath.rawURL.isEmpty {
cell = tableView.dequeueReusableCell(withIdentifier: "LinkPreviewCell", for: indexPath) as! LinkPreviewCell
} else if postAtIndexPath.quotedID > -1 {
cell = tableView.dequeueReusableCell(withIdentifier: "QuoteCell", for: indexPath) as! QuoteCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "PostCell", for: indexPath) as! PostCell
}
cell.isUserInteractionEnabled = true
cell.privacyDelegate = self
cell.shareDelegate = self
cell.likeDelegate = self
cell.linkPreviewDelegate = self
cell.reloadDelegate = self
postToIndexPath[postAtIndexPath.id] = indexPath
if parentView == "MyLikes" || parentView == "Trending" {
cell.privatePostButton.isHidden = true
cell.privatePostLabel.isHidden = true
}
cell.configureFor(post: postAtIndexPath,
liked: likesCache.postIsLiked(postId: postAtIndexPath.id),
postIdToAttributions: postIdToAttributions,
urlStringToOGData: urlStringToOGData,
imageURLStringToData: imageURLStringToData)
cell.contentView.layoutIfNeeded()
return cell
}
异步 Twitter 调用:
asynch Twitter call:
private func processForTwitter(og: OpenGraph, urlLessString: NSMutableAttributedString, completion:(() -> ())?) {
let ogURL = og[.url]!
let array = ogURL.components(separatedBy: "/")
let client = TWTRAPIClient()
let tweetID = array[array.count - 1]
if let tweet = twitterCache.tweet(forID: Int(tweetID)!) {
for subView in containerView.subviews {
subView.removeFromSuperview()
}
let tweetView = TWTRTweetView(tweet: tweet as? TWTRTweet, style: .compact)
containerView.addSubview(tweetView)
tweetView.translatesAutoresizingMaskIntoConstraints = false
tweetView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
tweetView.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
containerView.leftAnchor.constraint(equalTo: tweetView.leftAnchor).isActive = true
containerView.rightAnchor.constraint(equalTo: tweetView.rightAnchor).isActive = true
containerView.isHidden = false
postText.isHidden = false
} else {
client.loadTweet(withID: tweetID, completion: { [weak self] (t, error) in
if let weakSelf = self {
if let tweet = t {
weakSelf.twitterCache.addTweetToCache(tweet: tweet, forID: Int(tweetID)!)
}
}
if let complete = completion {
complete()
}
})`enter code here`
}
if urlLessString.string.isEmpty {
if let ogTitle = og[.title] {
postText.text = String(htmlEncodedString: ogTitle)
}
} else {
postText.attributedText = urlLessString
}
}
tableviewcontroller 中的完成块:
completion block in the tableviewcontroller:
func reload(postID: Int) {
tableView.beginUpdates()
self.tableView.reloadRows(at: [self.postToIndexPath[postID]!], with: .automatic)
tableView.endUpdates()
}
注意:这不会在 100% 的情况下发生,大概是依赖于网络.
NB: this doesn't happen 100% of the time, it is, presumably, network dependent.
推荐答案
事实证明,围绕 estimatedRowHeight
和 reloadRows
;解决方案,通过一个切线相关的 SO 问题,是在行高可用时缓存行高,如果在 heightForRow
中可用,则返回该行高.
Turns out there's weird, or at least I don't understand it, behavior around estimatedRowHeight
and reloadRows
; solution, via a tangentially related SO question, was to cache the row heights as they become available and return that if available in heightForRow
.
我猜它不会在重新加载时重新计算高度或其他东西?真的不明白具体为什么会这样,但我很高兴它确实如此!
I guess it doesn't recalculate the heights, or something, on a reload? Really don't understand specifically WHY this works, but I'm happy it does!
这篇关于自定义 UITableview 单元格偶尔会在其他单元格之上重叠/复制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!