我的 UICollectionView 无法使用 Swift 平滑滚动 [英] My UICollectionView does not scroll smoothly using Swift

查看:50
本文介绍了我的 UICollectionView 无法使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆