Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 82 additions & 69 deletions Sources/Views/ReloadableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ extension UICollectionView: ReloadableView {

@objc
open func reloadDataSynchronously() {
reloadData()

// Force a layout so that it is safe to call insert after this.
layoutIfNeeded()
DispatchQueue.main.async {
self.reloadData()
self.layoutIfNeeded() // Ensures layout is updated after reload
}
}

@objc
Expand All @@ -69,38 +69,43 @@ extension UICollectionView: ReloadableView {

@objc
open func perform(batchUpdates: BatchUpdates, completion: (() -> Void)?) {
performBatchUpdates({
if batchUpdates.insertItems.count > 0 {
self.insertItems(at: batchUpdates.insertItems)
}
if batchUpdates.deleteItems.count > 0 {
self.deleteItems(at: batchUpdates.deleteItems)
}
if batchUpdates.reloadItems.count > 0 {
self.reloadItems(at: batchUpdates.reloadItems)
}
for move in batchUpdates.moveItems {
self.moveItem(at: move.from, to: move.to)
}

if batchUpdates.insertSections.count > 0 {
self.insertSections(batchUpdates.insertSections)
}
if batchUpdates.deleteSections.count > 0 {
self.deleteSections(batchUpdates.deleteSections)
}
if batchUpdates.reloadSections.count > 0 {
self.reloadSections(batchUpdates.reloadSections)
}
for move in batchUpdates.moveSections {
self.moveSection(move.from, toSection: move.to)
}
}, completion: { _ in
completion?()
})
DispatchQueue.main.async {
self.performBatchUpdates({
if batchUpdates.insertItems.count > 0 {
self.insertItems(at: batchUpdates.insertItems)
}
if batchUpdates.deleteItems.count > 0 {
self.deleteItems(at: batchUpdates.deleteItems)
}
if batchUpdates.reloadItems.count > 0 {
self.reloadItems(at: batchUpdates.reloadItems)
}
for move in batchUpdates.moveItems {
self.moveItem(at: move.from, to: move.to)
}

if batchUpdates.insertSections.count > 0 {
self.insertSections(batchUpdates.insertSections)
}
if batchUpdates.deleteSections.count > 0 {
self.deleteSections(batchUpdates.deleteSections)
}
if batchUpdates.reloadSections.count > 0 {
self.reloadSections(batchUpdates.reloadSections)
}
for move in batchUpdates.moveSections {
self.moveSection(move.from, toSection: move.to)
}
}, completion: { _ in
completion?()
})
}
}

open func contentView(forIndexPath indexPath: IndexPath) -> UIView? {
DispatchQueue.main.async {
self.layoutIfNeeded() // Ensure the layout is up-to-date before querying
}
return self.cellForItem(at: indexPath)?.contentView
}
}
Expand All @@ -112,53 +117,61 @@ extension UITableView: ReloadableView {

@objc
open func reloadDataSynchronously() {
reloadData()
DispatchQueue.main.async {
self.reloadData()
self.layoutIfNeeded() // Ensures layout is updated after reload
}
}

@objc
open func registerViews(withReuseIdentifier reuseIdentifier: String) {
register(UITableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
register(UITableViewHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: reuseIdentifier)
}

@objc
open func perform(batchUpdates: BatchUpdates, completion: (() -> Void)?) {
beginUpdates()

// Update items.
if batchUpdates.insertItems.count > 0 {
insertRows(at: batchUpdates.insertItems, with: .automatic)
}
if batchUpdates.deleteItems.count > 0 {
deleteRows(at: batchUpdates.deleteItems, with: .automatic)
}
if batchUpdates.reloadItems.count > 0 {
reloadRows(at: batchUpdates.reloadItems, with: .automatic)
}
for move in batchUpdates.moveItems {
moveRow(at: move.from, to: move.to)
}
DispatchQueue.main.async {
self.beginUpdates()

// Update items.
if batchUpdates.insertItems.count > 0 {
self.insertRows(at: batchUpdates.insertItems, with: .automatic)
}
if batchUpdates.deleteItems.count > 0 {
self.deleteRows(at: batchUpdates.deleteItems, with: .automatic)
}
if batchUpdates.reloadItems.count > 0 {
self.reloadRows(at: batchUpdates.reloadItems, with: .automatic)
}
for move in batchUpdates.moveItems {
self.moveRow(at: move.from, to: move.to)
}

// Update sections.
if batchUpdates.insertSections.count > 0 {
insertSections(batchUpdates.insertSections, with: .automatic)
}
if batchUpdates.deleteSections.count > 0 {
deleteSections(batchUpdates.deleteSections, with: .automatic)
}
if batchUpdates.reloadSections.count > 0 {
reloadSections(batchUpdates.reloadSections, with: .automatic)
}
for move in batchUpdates.moveSections {
moveSection(move.from, toSection: move.to)
// Update sections.
if batchUpdates.insertSections.count > 0 {
self.insertSections(batchUpdates.insertSections, with: .automatic)
}
if batchUpdates.deleteSections.count > 0 {
self.deleteSections(batchUpdates.deleteSections, with: .automatic)
}
if batchUpdates.reloadSections.count > 0 {
self.reloadSections(batchUpdates.reloadSections, with: .automatic)
}
for move in batchUpdates.moveSections {
self.moveSection(move.from, toSection: move.to)
}

self.endUpdates()

completion?()
}

endUpdates()

completion?()
}

open func contentView(forIndexPath indexPath: IndexPath) -> UIView? {
DispatchQueue.main.async {
self.layoutIfNeeded() // Ensure the layout is up-to-date before querying
}
return self.cellForRow(at: indexPath)?.contentView
}
}
28 changes: 24 additions & 4 deletions Sources/Views/ReloadableViewLayoutAdapter+UICollectionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,28 @@ extension ReloadableViewLayoutAdapter: UICollectionViewDataSource {

/// - Warning: Subclasses that override this method must call super
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let arrangement = currentArrangement[safe: indexPath.section]?.items[safe: indexPath.item]

// Dequeue cell with unique reuse identifier
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
UIView.performWithoutAnimation {
arrangement?.makeViews(in: cell.contentView)

// Reset cell state
cell.isHidden = false
cell.contentView.subviews.forEach { $0.removeFromSuperview() }

// Configure cell content
if let arrangement = currentArrangement[safe: indexPath.section]?.items[safe: indexPath.item] {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main

UIView.performWithoutAnimation {
arrangement.makeViews(in: cell.contentView)
}
}

return cell
}

/// - Warning: Subclasses that override this method must call super
open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: reuseIdentifier, for: indexPath)
let arrangement: LayoutArrangement?
var arrangement: LayoutArrangement?
switch kind {
case UICollectionView.elementKindSectionHeader:
arrangement = currentArrangement[indexPath.section].header
Expand All @@ -65,6 +75,16 @@ extension ReloadableViewLayoutAdapter: UICollectionViewDataSource {
arrangement = nil
assertionFailure("unknown supplementary view kind \(kind)")
}

// Reset supplementary view state
view.subviews.forEach { $0.removeFromSuperview() }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

main


// Configure supplementary view content
if kind == UICollectionView.elementKindSectionHeader {
arrangement = currentArrangement[indexPath.section].header
} else {
arrangement = currentArrangement[indexPath.section].footer
}
UIView.performWithoutAnimation {
arrangement?.makeViews(in: view)
}
Expand Down
Loading