Diffable UICollectionView without fade animation on reload

Hi,

Note: Am required to support iOS 14, and so am unable to use some of the new APIs available in iOS 15 related to this question. I have also created a similar setup with a UITableView, however, am opting for the UICollectionView with list content as the collapsable sections are far nicer to work with.

Anyway, I have a simple UICollectionView setup using the UICollectionViewCompositionalLayout and UICollectionViewListCell to render a simple settings view.

Some of these views have accessories such as UISwitch elements and some display things like a .checkmark. They all render fine and ultimately they update to the expected state after applying the section snapshot. I expect this as the Identifiable ID has not changed, but the equatable check has. However, when the associated data item is updated it animates the change with a slight fade.

When I subclassed the UICollectionViewCompositionalLayout to take a closer look I noticed that the change is being made by deleting and inserting an item in the same location, rather than the expected reload action type.

I have also tried setting up so that the diffable data source only uses identifiers (where the cell registrations grab the relative item), but again when I reload the sections I get the slight fade.

Currently am using the following:

func setDisplaySections(_ sections: [Settings.Display.Section]) {
        let isInitialData = dataSource.snapshot().sectionIdentifiers.isEmpty
        var snapshot = NSDiffableDataSourceSnapshot<Settings.Display.Section.ID, ListItem>()
        let sectionIds = sections.map(\.id)
        snapshot.appendSections(sectionIds)
        sections.forEach { section in
            var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<ListItem>()
            // Append the section item as the layout is using the first item as the header.
            let headerItem = ListItem.header(id: section.id, title: section.title, isCollapsable: section.isCollapsable)
            sectionSnapshot.append([headerItem])

            // Append items to the section
            let items = section.items.map(transformToListItem)
            sectionSnapshot.append(items, to: headerItem)

            // Adjust expanded state
            let isExpanded = isSectionExpanded(section.id)
            if isInitialData, section.isCollapsable, !isExpanded {
                sectionSnapshot.collapse([headerItem])
            } else {
                sectionSnapshot.expand([headerItem])
            }
            dataSource.apply(sectionSnapshot, to: section.id, animatingDifferences: !isInitialData)
        }
    }

Question: I am wondering if there is a way to tell the collection view to just reload/update the cell without the insert/delete to avoid this slight fade when these values change. Or should I take another look at subclassing UICollectionViewCompositionalLayout to convert the insert/delete pairs for this scenario into the update type?

Also, am aware the UITableViewDiffableDataSource will let you assign the defaultRowAnimation - but it does not seem to let you assign per update type (insert/delete/reload etc). And assigning none will also cancel some of the accessory animations, assigning fade will produce the same issue as above.

Some screen grabs (unable to upload movie):

Before switch is toggled:

During animation of toggle:

For reference, To resolve this within our setup (and on time), I ended up making the Diffable data source use the <Section.ID, ListItem.ID> and load the relative section/item from a property stored on the view controller. Then in the data application method after the snapshots are applied, it runs through and calculates which cells need to reload their model and invokes a helper method.

This makes the snapshot only sort out inserts/deletes/moves, and then we handle the reloading. It's not the most ideal setup, however, until we can access some of the newer API's it will have to do.

Diffable UICollectionView without fade animation on reload
 
 
Q