diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f005978..1225d453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### Fixed +- Fixed an issue where animations would occur when dequeuing / reusing cells. A layout is now forced without animation before presentation. + ### Added ### Removed diff --git a/ListableUI/Sources/ListView/ListView.Delegate.swift b/ListableUI/Sources/ListView/ListView.Delegate.swift index 66a39143..356cf430 100644 --- a/ListableUI/Sources/ListView/ListView.Delegate.swift +++ b/ListableUI/Sources/ListView/ListView.Delegate.swift @@ -140,6 +140,13 @@ extension ListView item.willDisplay(cell: cell, in: collectionView, for: indexPath) self.displayedItems[ObjectIdentifier(cell)] = item + + UIView.performWithoutAnimation { + /// Force a layout of the cell before it is displayed, so that any implicit animations + /// are avoided. This ensures that cases like toggling a switch on and off are + /// not animated as the cell comes into view. + cell.layoutIfNeeded() + } } func collectionView( @@ -175,6 +182,13 @@ extension ListView headerFooter.collectionViewWillDisplay(view: container) self.displayedSupplementaryItems[ObjectIdentifier(container)] = headerFooter + + UIView.performWithoutAnimation { + /// Force a layout of the cell before it is displayed, so that any implicit animations + /// are avoided. This ensures that cases like toggling a switch on and off are + /// not animated as the cell comes into view. + container.layoutIfNeeded() + } } func collectionView( diff --git a/ListableUI/Sources/ListView/ListView.VisibleContent.swift b/ListableUI/Sources/ListView/ListView.VisibleContent.swift index d84bca24..cc534802 100644 --- a/ListableUI/Sources/ListView/ListView.VisibleContent.swift +++ b/ListableUI/Sources/ListView/ListView.VisibleContent.swift @@ -24,6 +24,13 @@ extension ListView let removed = self.items.subtracting(newItems) let added = newItems.subtracting(self.items) + // Note: We set these values _before_ we invoke `setAndPerform`, + // incase `setAndPerform` causes an external callback to trigger + // an update, which could cause this method to be re-entrant. + + self.items = newItems + self.headerFooters = newHeaderFooters + removed.forEach { $0.item.setAndPerform(isDisplayed: false) } @@ -31,9 +38,6 @@ extension ListView added.forEach { $0.item.setAndPerform(isDisplayed: true) } - - self.items = newItems - self.headerFooters = newHeaderFooters // Inform any state reader callbacks of the changes.