Skip to content

Refresh Bug on UICollectionReusableView #373

Open
@StefaniOSApps

Description

@StefaniOSApps

What do i want to do?

I use a UICollectionView and UICollectionReusableView for headers and footers. I would now like to remove animated the header in a section by an update.

Problem

The identity of the section remains unchanged so that the change is animated. Unfortunately, this means that the header + footer are not updated when I perform an update. If the identity of the section is changed with the update, the header and footer are updated - but not animated (only reload).

Workaround

viewModel.sections.subscribe(onNext: { _ in
   // requierd for header footer refresh animation
   self.collectionView.collectionViewLayout.invalidateLayout()
}).disposed(by: bag)

My Code

Init + Refresh Section

final class DashboardViewModel: BIACollectionViewModel {

  var sections: BehaviorRelay<[BIACollectionSection]>

  init() {
    self.sections = BehaviorRelay(value: [
      BIACollectionSection(
        identity: "1",
        header: HFSingleLineViewModel(text: "Do you need any help?")
        viewModels: [
          VehicleViewModel(identifier: 1)
        ])
    ])

    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
      self.sections.accept([
        BIACollectionSection(
          identity: "1",
          viewModels: [
            VehicleViewModel(identifier: 1)
          ])
      ])
    }
  }
}

AnimatableSectionModelType

struct BIACollectionSection: AnimatableSectionModelType {
  typealias Item = CollectionViewCellTypes

  var header: CollectionHeaderFooterViewRepresentable?
  var footer: CollectionHeaderFooterViewRepresentable?
  var items: [Item]
  private let customIdentity: String?
  var identity: String {
    if let identity = customIdentity {
      return identity
    }
    let hView = header?.identity ?? ""
    let fView = footer?.identity ?? ""
    return hView + "_" + fView
  }

  init(original: Self, items: [Item]) {
    self = original
    self.items = items
  }

  internal init(
    identity: String? = nil,
    header: CollectionHeaderFooterViewRepresentable? = nil,
    footer: CollectionHeaderFooterViewRepresentable? = nil,
    viewModels: [CollectionCellRepresentable]
  ) {
    self.customIdentity = identity
    self.header = header
    self.footer = footer
    self.items = viewModels.map({ $0.item })
  }
}

Init DataSource

self.dataSource = RxCollectionViewSectionedAnimatedDataSource<BIACollectionSection>(
  configureCell: { _, collectionView, indexPath, item in
    let item = item.cell(collectionView: collectionView, indexPath: indexPath)
    return item
  },
  configureSupplementaryView: { _, collectionView, kind, indexPath -> UICollectionReusableView in
    let section = viewModel.sections.value.section(at: indexPath.section)
    switch kind {
    case UICollectionView.elementKindSectionHeader:
      return section.header?.headerFooterInstance(collectionView, indexPath: indexPath) ?? UICollectionReusableView(frame: .zero)
    case UICollectionView.elementKindSectionFooter:
      return section.footer?.headerFooterInstance(collectionView, indexPath: indexPath) ?? UICollectionReusableView(frame: .zero)
    default:
      return UICollectionReusableView(frame: .zero)
    }
  }
)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions