UICollectionView 从 NSAttributedString 图像滚动滞后/断断续续

Posted

技术标签:

【中文标题】UICollectionView 从 NSAttributedString 图像滚动滞后/断断续续【英文标题】:UICollectionView laggy/choppy scrolling from NSAttributedString image 【发布时间】:2018-02-18 22:46:37 【问题描述】:

我正在制作一个简单的应用程序,允许用户每天写一两句话。

我有一个 UICollectionView 将每一天显示为一个单元格。在该单元格中,有一个 UITextView,用户可以在其中输入他们的文本。他们输入的文本保存在 Core Data 中。

每个单元格都使用用户输入的文本(从核心数据获取)填充 UITextView。但是如果用户那天没有输入文本,那么 UITextView 会填充一个 NSAttributedString,其中包含一个图像和一个字符串,以鼓励用户输入文本。

问题是带有 NSAttributedString 的单元格会导致 CollectionView 滚动非常缓慢和不稳定。

造成延迟的具体原因是 NSAttributedString 中的图像。图片来自xcassets。

那么我怎样才能在多个单元格上使用相同的图像(在 NSAttributedString 中)而不会有延迟滚动?

我遇到的可能的解决方案:

    异步预取或加载图像但我的图像在 xcassets 中。当您从某个地方获取/下载图像时,不是异步加载吗? 缓存图片但是如何缓存来自 xcassets 的图片呢?

ViewController.swift

    override func viewWillAppear(_ animated: Bool) 
         collectionView.delegate = self
         super.viewWillAppear(animated)
         collectionView.setNeedsLayout()
         collectionView.layoutIfNeeded()
    
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
       return dates.count
    
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
       let cellSize = CGSize(width: round(UIScreen.main.bounds.width * 0.8125), height: 469)
       return cellSize
    
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
        cell.fetchedResultsController = fetchedResultsController
        cell.date = dates[indexPath.item]
        return cell
    

CollectionViewCell.swift

    @IBOutlet var textView: UITextView!

    var date = Date() 
       didSet 
         loadTextViewData()
       
    

    required init?(coder decoder: NSCoder) 
          super.init(coder: decoder)!
          self.setNeedsLayout()
          self.layoutIfNeeded()
    

   func loadTextViewData()
        let entity = CoreDataMethods.fetchEntity(date: date)
    
        if (entity != nil)
            textView.attributedText = NSAttributedString(string:entity?.value(forKey: "textViewEntry") as! String)
         else 
            loadPromptText()
        
    

    func loadPromptText()
        let style = NSMutableParagraphStyle()
        style.lineSpacing = 10
        style.alignment = .center
        
        textView.attributedText = NSAttributedString(string: "Tap here to enter!" , attributes: [NSAttributedStringKey.paragraphStyle : style,  NSAttributedStringKey.font: UIFont(name: "Helvetica-Bold", size: 16.0)!])
      
        let attributedString = NSMutableAttributedString(attributedString:textView.attributedText )

        let textAttachment = NSTextAttachment()
        textAttachment.image =  #imageLiteral(resourceName: "EditIcon")
        textAttachment.image = UIImage(cgImage: textAttachment.image!.cgImage!, scale: CGFloat(7.0), orientation: .up)

        let attrStringWithImage = NSAttributedString(attachment: textAttachment)
        attributedString.append(attrStringWithImage)

        textView.attributedText = attributedString; 
    

【问题讨论】:

你为什么不创建一个静态属性来保存你的属性字符串? 我看到您每次调用 cellForRow 方法时都会读取 DB。自己不是很迟钝吗?您应该在更新单元格之前加载结果 【参考方案1】:

我的收藏视图遇到了同样的问题,我通过从情节提要中禁用收藏视图 Prefetch 来修复它,例如 this

【讨论】:

以上是关于UICollectionView 从 NSAttributedString 图像滚动滞后/断断续续的主要内容,如果未能解决你的问题,请参考以下文章

从 UICollectionView 中删除一个项目

从 UICollectionview 隐藏部分

通过 NSNotification 从 UICollectionView 中删除单元格

无法从 UITableViewCell 加载 UICollectionView

从 UIViewController 启动 UICollectionView

从 uiviewcontroller 操作 uicollectionviewcell 内的 uicollectionview