【发布时间】:2018-08-10 01:49:22
【问题描述】:
我有一个CollectionView,它根据message 类型(例如,文本、图像)使单元格出列。
我遇到的问题是,当我向上/向下滚动时 滚动非常不稳定,因此用户体验不是很好。这只会在第一次加载单元格时发生,之后滚动流畅。
有什么办法可以解决这个问题吗?这可能是在显示单元格之前获取数据所花费的时间的问题吗?
我不太熟悉在后台线程等上运行任务,并且不确定我可以进行哪些更改来完善数据预/获取等。请帮忙!
当视图加载时 Gif 显示向上滚动,当我尝试向上滚动时,它显示单元格/视图不稳定。
这是我的 func loadConversation(),它加载了 messages 数组
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 将单元格出列
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 自定义单元格类,它配置了一个图像消息):
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 我的自定义单元格类中的函数
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
【问题讨论】:
-
您的单元格中是否有任何 api 调用??
-
我已将代码粘贴到我原来的问题上面的自定义
ConversationCell类中,唯一的调用是通过sd_setImage加载图像,但即使没有图像也会发生这种情况装载。我还有loadConversation()函数,它通过一个名为的单例类方法从 Firebase 获取数据 -
使用时间分析器分析您的应用程序。它将显示哪个代码需要很长时间。你在奇怪的地方有很多代码。就像设置你的影子......应该从笔尖而不是布局子视图等中醒来......并且“切换自动布局”的东西看起来很狡猾......你为什么这样做?
-
我第一次在任何应用程序上运行时间分析器,我应该寻找什么?如何分享我的结果?
-
@Fogmeister 我已经编辑了我的问题以包含我的时间配置文件结果的屏幕截图,我可以看到加载聊天的自定义单元格是一些最大的罪魁祸首。我只是不知道如何解决我的问题?
标签: swift uicollectionview uicollectionviewcell