我的 UICollectionView 无法使用 Swift 平滑滚动 [英] My UICollectionView does not scroll smoothly using Swift
问题描述
我有一个 CollectionView
,它根据 message
类型(例如文本、图像)使单元格出列.
I have a CollectionView
which dequeues a cell depending on the message
type (eg; text, image).
我遇到的问题是,当我向上/向下滚动时滚动真的很断断续续,因此用户体验不是很好.这只会在第一次加载单元格时发生,之后滚动流畅.
The problem I am having is that when I scroll up/down the scroll is really choppy and thus not a very good user experience. This only happens the first time the cells are loaded, after that the scrolling is smooth.
有什么想法可以解决这个问题吗?这可能是在显示单元格之前获取数据所花费的时间的问题吗?
我不太熟悉在后台线程等上运行任务,并且不确定我可以做哪些更改来完善数据预取/获取等.请帮忙!
I am not too familiar with running tasks on background threads etc. and not sure what changes I can make to prefect the data pre/fetching etc.. please help!
当视图加载时 Gif 显示向上滚动,当我尝试向上滚动时,它显示单元格/视图断断续续.
The Gif shows scroll up when the view loads, it shows the cells/view being choppy as I attempt to scroll up.
这是我的 func loadConversation()
,它加载了 messages
数组
This is my func loadConversation()
which loads the messages
array
func loadConversation(){
DataService.run.observeUsersMessagesFor(forUserId: chatPartnerId!) { (chatLog) in
self.messages = chatLog
DispatchQueue.main.async {
self.collectionView.reloadData()
if self.messages.count > 0 {
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .bottom , animated: false)
}
}
}//observeUsersMessagesFor
}//end func
这是我的 cellForItemAt,它使单元格出列
This is my cellForItemAt which dequeues cells
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let message = messages[indexPath.item]
let uid = Auth.auth().currentUser?.uid
if message.fromId == uid {
if message.imageUrl != nil {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellImage", for: indexPath) as! ConversationCellImage
cell.configureCell(message: message)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellSender", for: indexPath) as! ConversationCellSender
cell.configureCell(message: message)
return cell
}//end if message.imageUrl != nil
} else {
if message.imageUrl != nil {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCellImageSender", for: indexPath) as! ConversationCellImageSender
cell.configureCell(message: message)
return cell
} else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ConversationCell", for: indexPath) as! ConversationCell
cell.configureCell(message: message)
return cell
}
}//end if uid
}//end func
这是我的 ConversationCell
类,它通过 cellForItemAt
配置一个用于出列的自定义单元格(注意:此外还有另一个 ConversationCellImage
自定义单元格类配置图像消息):
This is my ConversationCell
class which configures a custom cell for dequeueing by cellForItemAt
(note: in addition there another ConversationCellImage
custom cell class which configures an image message):
class ConversationCell: UICollectionViewCell {
@IBOutlet weak var chatPartnerProfileImg: CircleImage!
@IBOutlet weak var messageLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
chatPartnerProfileImg.isHidden = false
}//end func
func configureCell(message: Message){
messageLbl.text = message.message
let partnerId = message.chatPartnerId()
DataService.run.getUserInfo(forUserId: partnerId!) { (user) in
let url = URL(string: user.profilePictureURL)
self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
}//end getUserInfo
}//end func
override func layoutSubviews() {
super.layoutSubviews()
self.layer.cornerRadius = 10.0
self.layer.shadowRadius = 5.0
self.layer.shadowOpacity = 0.3
self.layer.shadowOffset = CGSize(width: 5.0, height: 10.0)
self.clipsToBounds = false
}//end func
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//toggles auto-layout
setNeedsLayout()
layoutIfNeeded()
//Tries to fit contentView to the target size in layoutAttributes
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
//Update layoutAttributes with height that was just calculated
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height) + 18
layoutAttributes.frame = frame
return layoutAttributes
}
}//end class
时间资料结果:
流程布局代码
if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout,
let collectionView = collectionView {
let w = collectionView.frame.width - 40
flowLayout.estimatedItemSize = CGSize(width: w, height: 200)
}// end if-let
preferredLayoutAttributesFitting
函数在我的自定义单元类中
preferredLayoutAttributesFitting
function in my custom cell class
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//toggles auto-layout
setNeedsLayout()
layoutIfNeeded()
//Tries to fit contentView to the target size in layoutAttributes
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
//Update layoutAttributes with height that was just calculated
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height) + 18
layoutAttributes.frame = frame
return layoutAttributes
}
解决方案:
extension ConversationVC: UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var height: CGFloat = 80
let message = messages[indexPath.item]
if let text = message.message {
height = estimateFrameForText(text).height + 20
} else if let imageWidth = message.imageWidth?.floatValue, let imageHeight = message.imageHeight?.floatValue{
height = CGFloat(imageHeight / imageWidth * 200)
}
let width = collectionView.frame.width - 40
return CGSize(width: width, height: height)
}
fileprivate func estimateFrameForText(_ text: String) -> CGRect {
let size = CGSize(width: 200, height: 1000)
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: size, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 16)], context: nil)
}
}//end extension
推荐答案
首先,让我们尝试找到出现此问题的确切位置.
First thing first, let's try finding the exact location where this problem is arising.
尝试 1:
评论这一行
//self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
并运行您的应用以查看结果.
And run your app to see the results.
尝试 2:
将该行放在异步块中以查看结果.
Put that line in async block to see the results.
DispatchQueue.main.async {
self.chatPartnerProfileImg.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"), options: [.continueInBackground, .progressiveDownload], completed: nil)
}
尝试3:注释设置圆角半径的代码
Try 3: Comment the code for setting corner radius
/*self.layer.cornerRadius = 10.0
self.layer.shadowRadius = 5.0
self.layer.shadowOpacity = 0.3
self.layer.shadowOffset = CGSize(width: 5.0, height: 10.0)
self.clipsToBounds = false*/
分享您的尝试 1、2 和 3 的结果,然后我们可以更好地了解问题所在.
Share your results for Try 1, 2 and 3 and then we can get the better idea about where the problem lies.
希望通过这种方式我们可以得到闪烁背后的原因.
Hope this way we can get the reason behind flickering.
这篇关于我的 UICollectionView 无法使用 Swift 平滑滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!