Как перерисовать невидимые UICollectionViewCell после поворота готовы для повторного использования?

Как перерисовать невидимый UICollectionViewCell готовы для повторного использования???

Один из подходов, о которых я подумал, заключался в коде в функции Layout Cell prepareForReuse, однако он работает неоптимально, так как вызывает больше перерисовки, чем требуется.

Справочная информация: необходимо вызвать drawRect для ячеек после изменения ориентации, которые не видны в данный момент, но всплывают для использования и не были перерисованы, так что пока я вижу только это prepareForReuse было бы уместно. Проблема в том, что я перерисовываю все ячейки "повторного использования", в то время как я действительно хочу перерисовать только те всплывающие окна, которые были созданы во время предыдущей ориентации устройства.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Итак, в настоящее время я делаю это:

В ViewController:

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?
}

В классе Layout Cell:

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 выше. Снимок, сделанный после изменения ориентации и чуть-чуть прокрутки вверх:

введите описание изображения здесь

3 ответа

Решение

Я думаю, что у меня есть это сейчас здесь:

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", однако.

Вы можете реализовать какую-то связь между ячейками и контроллером представления, содержащим представление сбора (протокол и делегат или переданный блок или даже прямую ссылку на VC). Затем Вы можете запросить у контроллера вида изменения поворота.

Это немного грязно, но если у вас есть какое-то отслеживание вращения в вашем контроллере представления, вы можете отфильтровать setNeedsDisplay с помощью простого оператора if.

У меня были похожие задачи обновления ячеек, которые уже были отображены и за пределами экрана. В то время как циклическое прохождение ячеек ALLL может быть невозможным - обновление / зацикливание невидимых ячеек есть. Если это ваш вариант использования - тогда читайте дальше. Предварительное предупреждение - если вы добавляете такой код - объясните, почему вы это делаете. Это своего рода анти-паттерн - но может помочь исправить эту ошибку и помочь в доставке вашего приложения, хотя и добавляет ненужную сложность. Не используйте это в нескольких местах в приложении.

Любая ячейка collectionview, которая деинициализирована (за пределами экрана и подвергается повторной инициализации), должна автоматически отписываться.

Шаблон уведомления

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) 

Шаблон делегата

Можно упростить это.... упражнение для читателя. только не сохраняйте ячейки (используйте слабую ссылку) - иначе у вас будут утечки памяти.

Другие вопросы по тегам