我有一个COALESCE(A,B)
,它显示带有图像和一些文本的单元格。数据是按需请求的-我首先请求10行数据,然后再请求10行,依此类推。我在$contracts = $rp->createQueryBuilder('c')
->select('c')
->addSelect('COALESCE(c.updatedAt,c.createdAt) AS HIDDEN orderDate')
->orderBy('orderDate', 'DESC')
->getQuery()->getResult();
中进行此操作。问题是,当我收到数据并需要更新UITableView
时,有时会跳转和/或闪烁。我打电话给tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
。这是代码的一部分:
tableview
像这样返回的单元格高度是恒定的:
reloadData
我正在使用Kingfisher下载和缓存图像。这是来自数据源的更多代码:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
DispatchQueue.global(qos: .background).async {
if indexPath.row + 5 >= self.brands.count && !BrandsManager.pendingBrandsRequest {
BrandsManager.getBrands() { (error, brands) in
self.brands.append(contentsOf: brands as! [Brand])
DispatchQueue.main.async {
UIView.performWithoutAnimation {
self.brandsTableView.reloadData()
}
}
}
}
}
}
如何避免滚动时表格视图的闪烁和跳动?我查看了一些类似的问题,但找不到适合我的案例的解决方案。
答案 0 :(得分:1)
如果要将数据附加到tableView的末尾,请不要调用reloadData,这将强制重新计算并重新绘制所有单元格。而是使用UITableView.insertRows(at:with:),如果您使用.automatic并执行现有的单元格放置,则它将执行适当的插入动画。
答案 1 :(得分:1)
要消除跳跃问题,您需要将estimatedHeightForRowAt
设置为与行高相同。假设您没有性能问题,只需执行以下操作即可:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return self.tableView(tableView, heightForRowAt: indexPath)
}
或者如果单元格高度恒定,则可以执行tableView.estimatedRowHeight = 70.0
。
之所以会这样,是因为重新加载时的表格视图将estimatedRowHeight
用于不可见的单元格,当估计的高度与实际高度不同时会导致跳转。给您一个想法:
比方说,估计高度为50
,而实际高度为75
。现在您已经向下滚动,以使10个单元格不在屏幕上,您有10*75 = 750
个像素的内容偏移量。否,当重新加载发生时,表视图将忽略隐藏了多少个单元并尝试对其进行重新计算。它将继续重用估计的行高,直到找到应该可见的索引路径。在此示例中,它开始使用索引estimatedHeightForRow
调用您的[0, 1, 2...
,并将offset
增加50
,直到到达您的内容偏移量仍为750
。因此,这意味着它可以索引750/50 = 15
。这样会在重新加载时从单元格10
跳转到单元格15
。
关于闪烁,有很多可能性。通过仅重载已更改的数据源部分,可以避免重载不需要重载的单元。就您而言,这意味着要插入新行,例如:
tableView.beginUpdates()
tableView.insertRows(at: myPaths, with: .none)
tableView.endUpdates()
您甚至看到闪烁似乎还是很奇怪。如果仅图像闪烁,则问题可能出在其他地方。即使已经缓存了图像,获取这样的图像通常也是异步操作。您可以通过检查是否确实需要更新资源来避免这种情况。如果您的单元格已经在显示您要显示的图像,则没有理由应用新资源:
if let url = BrandsManager.brandLogoURL(forLogoName: brand.logo!) {
if url != cell.currentLeftImageURL { // Check if new image needs to be applied
let resource = ImageResource(downloadURL: url, cacheKey: url.absoluteString)
cell.currentLeftImageURL = url // Save the new URL
cell.leftImageView.kf.setImage(with: resource)
}
} else {
print("Cannot form url for brand logo")
}
我宁愿将此代码放到单元格本身中
var leftImageURL: URL {
didSet {
if(oldValue != leftImageURL) {
let resource = ImageResource(downloadURL: url, cacheKey: url.absoluteString)
leftImageView.kf.setImage(with: resource)
}
}
}
但这完全取决于您。