RxDataSources flashing and flickering on every change in the datasource content

843 views Asked by At

Initially the app shows UIViewCollection with one section and then new sections appears after receiving the content. A user scrolls the collection and new sections add to the bottom of the collection.

I use MVVM, so in my ViewModel I add a new section to the content array (model.content) and then notify the Publisher that binded to collectionView.rx.items(dataSource: self.dataSource).

So every time I add the section the collection is flashing and all cells are reloading that makes horrible user experience everything flashing, flickering, pictures disappearing and appearing. Is there a way not to reload all the collection but only the difference. I thought it should work like this by default. Maybe the method of notifying the BehaviorSubject is wrong idea?

I also tried to use the RxTableViewSectionedAnimatedDataSource but in this way everything disappearing and move the user to the very top of the collection view after every new section had beed added.

Please any idea why would all collection should be reloaded if I just added one section to the bottom, how to prevent it?

typealias ContentDataSource = RxCollectionViewSectionedReloadDataSource<ContentSection>

class ContentViewController: BaseViewController<ContentViewModel> {

    func setupBindings() {
         viewModel?.sectionItemsSubject
                .bind(to: collectionView.rx.items(dataSource: self.dataSource))
                .disposed(by: self.disposeBag)
    }
}


class ContentViewModel: BaseViewModel<ContentModel> {

    lazy var sectionItemsSubject = BehaviorSubject<[ContentSection]>(value: model.content)

    func updateGeneratedSection(_ section: ContentSection) {
        model.content.append(item)
        sectionItemsSubject.onNext(self.model.content)
    }
}

struct ContentModel {
  
    var content: [ContentSection] = []
}

EDITED:

struct ContentSection {
    
    var id: String
    var items: [Item]
    var order: Int
}

extension ContentSection: SectionModelType {
    
    typealias Item = ItemCellModel
    
    init(original: ContentSection, items: [ItemCellModel]) {
        self = original
        self.items = items
    }
}

struct ItemCellModel {

    let id: String
    let img: String
   
    
    init(id: String, img: String) {
       self.id = id
       self.img = img
   }
}
2

There are 2 answers

0
CloudBalancing On BEST ANSWER

Your model probably dont conform to the protocols needed correctly and the diff checker cannot identify cell models that are they same, thus it renders the whole collection view again. Please see the documentation about that:

‘’’ Supports extending your item and section structures just extend your item with IdentifiableType and Equatable, and your section with AnimatableSectionModelType ‘’’

https://github.com/RxSwiftCommunity/RxDataSources

In addition you can follow this example - https://bytepace.medium.com/bring-tables-alive-with-rxdatasources-rxswift-part-1-db050fbc2cf6.

2
Daniel T. On

CloudBalancing's answer is correct. Your ContentSection type is wrong... Try this:

typealias ContentSection = AnimatableSectionModel<ContentSectionModel, ItemCellModel>

struct ContentSectionModel: IdentifiableType {
    var identity: String
    var order: Int
}

struct ItemCellModel: IdentifiableType, Equatable {
    let identity: String
    let img: String
}