iosswiftuikitrx-swiftrxdatasources

Last visible cell in CollectionView disappears when updating first visible cell's content


I have a weird behavior using RxDataSources. I am using an RxCollectionViewSectionedAnimatedDataSource. I have a button inside each cell in the collection view, which reveals some content. This content is displayed through the built-in animations the library provides. When the first cell of the list is not appearing entirely, which means I've scrolled a bit and only part of the cell is showing, if I tap on the button (located at the bottom of the cell), the last visible cell on the screen disappears and reappears entirely for a quick second. I believe this might be due to the built-in animations in the library, however, it looks too much like a bug.

Here is how I have implemented things. The data source:

let dataSource = RxCollectionViewSectionedAnimatedDataSource<OfferSection>(
   animationConfiguration: AnimationConfiguration(insertAnimation: .none, reloadAnimation: .none, deleteAnimation: .none), configureCell: {
   [unowned self] dataSource, collectionView, indexPath, element in
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OfferCollectionViewCell.identifier, for: indexPath) as! OffersCollectionViewCell
     cell.set(offer: element)
     cell.findOfferButton.rx.tap.map{indexPath}.compactMap{$0}.map{ index in
     (element, index.row)}.bind(to: self.viewModel.input.viewOffer).disposed(by: cell.disposeBag)
     cell.redeemButton.rx.tap.map{element}.bind(to: self.viewModel.input.redeemOffer).disposed(by: cell.disposeBag)
     return cell
})

viewModel.output.offers.map{ [OfferSection(header: "", items: $0)] }.drive(self.offersCollectionView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)

My OfferSection object looks like this:

struct OfferSection: AnimatableSectionModelType {
    var header: String
    var items: [Offer]
    
    var identity: Int {
        return 0
    }
}

extension OfferSection {
    typealias Identity = Int
    typealias CustomDataAlias = Offer
    
   init(original: OfferSection, items: [Offer]) {
    self = original
    self.items = items
  }
}

My Offer object conforms to Equatable as well as IdentifiableType, as advised in the docs.

struct Offer: IdentifiableType, Equatable {
    let id: Int?
    let name: String
    let path: String?
    let offerLocation: String
    let email: String?
    let section: String
    let categories: [String]
    
    let uniqueId = UUID().uuidString
    var identity: String {
       return uniqueId
    }

    
    static func == (lhs: Offer, rhs: Offer) -> Bool {
        lhs.id == rhs.id && lhs.name == rhs.name && lhs.offerLocation == rhs.offerLocation
    }
}

I am wondering, maybe I have done something wrong?


Solution

  • I see a number of problems in the code you show, likely there are others...

    If making the above changes doesn't fix your problem. Update the question with more information.

    Because of the problems above, what is likely happening is that the data source is forced to do a complete data reload for every update (rather than just updating the specific cells that have changed) and you are seeing artifacts from that.