gpt4 book ai didi

ios - Twitter 让 UITableView 滚动流畅的技巧是什么?

转载 作者:行者123 更新时间:2023-11-28 08:25:36 25 4
gpt4 key购买 nike

我在改进 UITableView 的滚动时遇到了问题,它的自定义单元格是使用自动布局布局的。我有两种不同高度的自定义 UITableViewCell(一种大约 200px,一种大约 500px)我尝试了很多东西,包括:

  1. 缓存 UITableViewCells 的高度
  2. 使用自动尺寸和估计行高
  3. 计算 UITableViewCells 的高度(这可能需要一些研究,任何人都有使用自定义 tableviewcell 执行此操作的正确方法的链接?)
  4. 使用不透明 View
  5. 尝试使用仪器来查看减速发生的位置
  6. 将代码从 cellForRowAt 移至 willDisplayCell
  7. 异步缓存和显示属性文本。
  8. 异步缓存和显示图像。

以及遵循许多声称可以提高滚动速度的在线指南。然而,滚动仍然生涩!

此外,当我尝试滚动到顶部单元格时,它有时无法到达顶部。我想估计的单元格高度与此有关,但由于单元格的高度各不相同,因此很难做到正确。

仪器表明,当我将文本设置到我的单元格标签中时,我的代码速度变慢(这是调整单元格高度的位)。

我正在尝试弄清楚 Twitter 应用程序(它与我的 UITableView 具有基本相同的功能,具有属性文本和图像等)如何具有如此出色的滚动效果。我不久前看到他们的一篇博客文章说如何对所有内容使用 drawRect,但是,我很确定他们现在不会那样做。有人对他们如何实现 60fps 的平滑滚动有任何见解吗?

我的代码

所以首先我的两个表格单元格具有以下结构:

表格单元格 1:

 - UITableViewCell
- UIView (content view)
- UIView (Shadow view)
- UIView (Card background)
- UIView x 3
- UIButton x 5
- UILabel x 2
- UITextView

我将 UIView 称为 shadow viewcard background 的原因是我将 shadowPath 添加到 shadow views 层,它是一个 UIBezierPath。然后我将半径添加到 card background。这两个不能在同一层上完成,因为半径仅在两个角中,并且在尝试同时具有阴影和半径时会出现问题。

表格单元格 2:

 - UITableViewCell
- UIView (content view)
- UIView (Shadow view)
- UIView (Card background)
- UIView x 3
- UIButton x 5
- UILabel x 3
- UITextView
- UIImageView x 2

这使用相同的代码来添加阴影和圆角。

要获取行的估计高度,我使用以下代码:

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
let type = model.dataContent[indexPath.row]["type"].stringValue

if type == MediaType.text.rawValue {
return 150
} else {
return 500
}
}

在我的 UITableViewController 的 cellForRowAt 中,我有以下代码:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Create the custom cell
let mediaTableCellIdentifier = "MediaCell"
let textTableCellIdentifier = "TextCell"

let type = MediaType(rawValue: model.dataContent[indexPath.row]["type"].stringValue)

var cell: TableCell!
if type == .text {
cell = tableView.dequeueReusableCell(withIdentifier: textTableCellIdentifier, for: indexPath) as! TableTextCell
if flowState == .individualPost {
(cell as! TableTextCell).expandView()
}
} else {
cell = tableView.dequeueReusableCell(withIdentifier: mediaTableCellIdentifier, for: indexPath) as! TableMediaCell
(cell as! TableMediaCell).postImageView.image = nil
}

cell.delegate = self

if type == .image {
let cell = cell as! TableMediaCell
let urlString = model.dataContent[indexPath.row]["img"]["loc"].stringValue

// Check if we have an image stored in our cache for the image URL. If not, download it.
if let cellImage = model.imageCache[urlString] {
cell.postImageView.image = cellImage
}
else {
model.downloadImage(
atIndexPath: indexPath,
type: type!,
progress: { percentage in
cell.progressView.isHidden = false
cell.progressView.updateCirclePath(percentage: percentage)
},
completion: { [weak self] error, image in
if let strongSelf = self {
if error == nil {
// Store the image in to our cache
strongSelf.model.imageCache[urlString] = image
// Update the cell with our image
if let cellToUpdate = tableView.cellForRow(at: indexPath) as? TableMediaCell {
cellToUpdate.postImageView.image = image
cellToUpdate.progressView.resetCircleAnimation()
cellToUpdate.progressView.isHidden = true
}
}
else {
print("Error downloading image: \(error!.localizedDescription)")
}
}
}
)
}
} else if type == .video {
let cell = cell as! TableMediaCell
let urlString = "\(CloudFrontURL.video.rawValue)/\(model.dataContent[indexPath.row]["video"]["loc"].stringValue)"
if let cellVideo = model.videoCache[urlString] {
cell.videoPlayer = AVPlayer(playerItem: AVPlayerItem(asset: cellVideo))
cell.videoPlayer!.actionAtItemEnd = AVPlayerActionAtItemEnd.none
cell.videoView.playerLayer.player = cell.videoPlayer
} else {
let videoURL = URL(string: urlString)

cell.videoPlayer = AVPlayer(url: videoURL!)
model.videoCache[urlString] = cell.videoPlayer?.currentItem?.asset
cell.videoPlayer!.actionAtItemEnd = AVPlayerActionAtItemEnd.none

cell.videoView.playerLayer.player = cell.videoPlayer
}
}

cell.caption.text = model.dataContent[indexPath.row]["caption"].stringValue
cell.caption.isHidden = true
model.retrieveCaption(at: indexPath, forCell: cell, withFont: cell.caption.font!) { (caption, cellToUpdate) in
if let theCell = cellToUpdate {
theCell.caption.attributedText = caption
theCell.caption.isHidden = false
}
}

cell.commentCount.text = model.dataContent[indexPath.row]["commentsCount"].stringValue

// Enable/Disable the controls based on our settings
cell.controlsEnabled = controlsEnabled
// Provide each cell with our data
cell.model = model
// Setting this makes the controls update its data automatically.
cell.indexPath = indexPath

// If we've reached the last post in our loaded data, get the next page of posts (unless it's an individual post).
if (indexPath.row == model.dataContent.count - 3 && !lastItemReached && flowState != .individualPost) {
stateMachine.enterState(.retrievingNextPage)
}

return cell
}

当我设置两个 UITableViewCells 的 indexPath 时,将在自定义单元格类中调用此代码以更新单元格:

var indexPath: IndexPath {
get {
// Return the internalIndexPath when we ask for the indexPath.
return internalIndexPath
}
set {
// Set the internalIndexPath to the value supplied to indexPath.
internalIndexPath = newValue

// Calculate the number of points on a post.
let points = model.dataContent[self.indexPath.row]["upVotes"].intValue - model.dataContent[self.indexPath.row]["downVotes"].intValue
pointsLabel.text = "\(points)"
// Show the upload time of the post.
let uploadTimeString = model.dataContent[self.indexPath.row]["timestamp"].stringValue

let date = DateFormatter.formatter.date(from: uploadTimeString)
let dateString = date?.relativeTime
uploadTime.text = dateString

if let type = MediaType(rawValue: model.dataContent[self.indexPath.row]["type"].stringValue) {
self.type = type
}

/// Adjust up/down arrows
if (model.dataContent[self.indexPath.row]["userVote"]["likeState"] != nil) {
switch model.dataContent[self.indexPath.row]["userVote"]["likeState"].stringValue {
case LikeState.Likes.rawValue:
thumbsUpButton.isSelected = true
thumbsDownButton.isSelected = false
case LikeState.Dislikes.rawValue:
thumbsUpButton.isSelected = false
thumbsDownButton.isSelected = true
case LikeState.Neither.rawValue:
thumbsUpButton.isSelected = false
thumbsDownButton.isSelected = false
default:
break
}
} else {
thumbsUpButton.isSelected = false
thumbsDownButton.isSelected = false
}
}
}

最佳答案

您的 UITableView 显示缓慢的一个非常明显的原因是您的 cellForRowAtIndexPath 太长了。你需要重构你的代码。保持 Cell 声明本身简短。

最好的做法是在 cellForRowAtIndexPath 中声明 Cell,并调用一个 bindData 函数来用内容填充 Cell。例如:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

if indexPath.section == 0 {

let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! Cell

let content = contentArray[indexPath.row]
cell.bindData(content)

return cell
}
}

extension Cell {
bindData(content: ContentStruct) {
label.text = content.name
}
}

同样在您的情况下,您应该在设置内容的函数和设置属性的函数之间进行重构。让每个功能更短。

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

if indexPath.section == 0 {

let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! Cell

let content = contentArray[indexPath.row]
cell.bindData(content)
cell.setProperties

return cell
}
}

extension Cell {
bindData(content: ContentStruct) {
label.text = content.name
}

setProperties() {

// set stuff like:
// Enable/Disable the controls based on our settings
cell.controlsEnabled = controlsEnabled
// Provide each cell with our data
cell.model = model
// Setting this makes the controls update its data automatically.
cell.indexPath = indexPath

// If we've reached the last post in our loaded data, get the next page of posts (unless it's an individual post).
if (indexPath.row == model.dataContent.count - 3 && !lastItemReached && flowState != .individualPost) {
stateMachine.enterState(.retrievingNextPage)
}
}
}

关于ios - Twitter 让 UITableView 滚动流畅的技巧是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40112211/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com