6

如何在重用发生时重绘不可见的 UICollectionViewCell 准备好???

我想到的一种方法是根据布局单元 prepareForReuse 函数中的代码,但是虽然它的工作方式不是最佳的,因为它会导致更多的重新绘制然后需要。

背景:需要在drawRect当前不可见的方向更改后触发单元格,但弹出以供使用且尚未重绘,到目前为止我只能看到这prepareForReuse是合适的。问题是我正在重新绘制所有“重用”单元格,而我真的只想重新绘制最初弹出的那些在设备的先前方向位置期间创建的那些。

附加信息:所以目前我正在这样做:

在视图控制器中:

override func viewWillLayoutSubviews() {
    // Clear cached layout attributes (to ensure new positions are calculated)
    (self.cal.collectionViewLayout as! GCCalendarLayout).resetCache()
    self.cal.collectionViewLayout.invalidateLayout()

    // Trigger cells to redraw themselves (to get new widths etc)
    for cell in self.cal?.visibleCells() as! [GCCalendarCell] {
        cell.setNeedsDisplay()
    }

    // Not sure how to "setNeedsDisplay" on non visible cells here?
}

在布局单元类中:

override func prepareForReuse() {
    super.prepareForReuse()
    // Ensure "drawRect" is called (only way I could see to handle change in orientation
    self.setNeedsDisplay() 
    // ISSUE: It does this also for subsequent "prepareForReuse" after all
    // non-visible cells have been re-used and re-drawn, so really
    // not optimal
}

没有上面 prepareForReuse 中的代码会发生什么的示例。在方向更改后拍摄的快照,并且在向上滚动一点后拍摄:

在此处输入图像描述

4

3 回答 3

5

我想我现在在这里:

import UIKit

@IBDesignable class GCCalendarCell: UICollectionViewCell {
    var prevBounds : CGRect?

    override func layoutSubviews() {
        if let prevBounds = prevBounds {
            if !( (prevBounds.width == bounds.width) && (prevBounds.height == bounds.height) ) {
                self.setNeedsDisplay()
            }
        }
    }

    override func drawRect(rect: CGRect) {
        // Do Stuff
        self.prevBounds = self.bounds
    }

}

注意到此检查在“prepareForReuse”中不起作用,因为此时单元尚未应用轮换。然而,似乎在“layoutSubviews”中工作。

于 2015-10-24T00:49:41.750 回答
1

您可以在单元格和持有集合视图的视图控制器之间实现某种通信(协议和委托或传递的块,甚至直接引用 VC)。然后您可以向视图控制器询问旋转更改。

它有点乱,但是如果您的视图控制器中有某种​​旋转跟踪,您可以使用简单的 if 语句过滤 setNeedsDisplay。

于 2015-10-29T14:51:56.340 回答
0

我在更新已经显示和关闭屏幕的单元格时遇到了类似的挑战。虽然循环遍历所有单元格可能是不可能的 - 刷新/循环遍历不可见的单元格是可行的。如果这是您的用例,请继续阅读。预警告 - 如果您要添加此类代码 - 请解释您这样做的原因。这是一种反模式 - 但可以帮助修复该错误并帮助发布您的应用程序,尽管增加了不必要的复杂性。不要在应用程序的多个位置使用它。

任何取消初始化(离开屏幕并被回收)的 collectionviewcell 都应该自动取消订阅。

通知模式

let kUpdateButtonBarCell = NSNotification.Name("kUpdateButtonBarCell")

class Notificator {
     static func fireNotification(notificationName: NSNotification.Name) {
          NotificationCenter.default.post(name: notificationName, object: nil)
     }
}

extension UICollectionViewCell{
    func listenForBackgroundChanges(){
         NotificationCenter.default.removeObserver(self, name: kUpdateButtonBarCell, object: nil)
        NotificationCenter.default.addObserver(forName:kUpdateButtonBarCell, object: nil, queue: OperationQueue.main, using: { (note) in

            print( " contentView: ",self.contentView)

        })
    }
}



override func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell! {
    let cell =  collectionView.dequeueReusableCellWithReuseIdentifier("die", forIndexPath: indexPath) as UICollectionViewCell
    cell.listenForBackgroundChanges()
    return cell
}


 // Where appropriate broadcast notification to hook into all cells past and present
 Notificator.fireNotification(notificationName: kUpdateButtonBarCell) 

委托模式

可以简化这个....读者的练习。只是不要保留单元格(使用弱链接) - 否则你会有内存泄漏。

于 2017-03-24T16:32:14.397 回答