For UITableViewCells and UICollectionViewListCells, their contentView.layoutMarginsGuide respect the colletionView's layoutMarginsGuide automatically, which can be 16 or 20 points horizontally.
This is the expected behavior.
But for regular UICollectionViewCells with a regular compositional layout, their contentView.layoutMarginsGuide are defaulted to 8 points.
I don't see where I can hook into and change the layout margins of the cells . I've looked into contentInset property and contentInsetReference property of section and item when constructing a compositional layout, but with no luck, their intentions are to change the width of the cells themselves.
Post
Replies
Boosts
Views
Activity
From what I concluded, a diffable data source is designed to insert/delete/update/move only the differences from the new snapshot (if animatingDifferences is true), for those irrelevent cells, they should not be reloaded.
But whenever I apply a snapshot, even if the new snapshot is exactly the current one from the data source, almost every on-screen cells got reloaded. Here's a simple test view controller:
swift
import UIKit
class CollectionViewController: UIViewController {
enum Section: Hashable {
case main
}
struct Item: Hashable {
let id: String
}
private lazy var dataSource: UICollectionViewDiffableDataSourceSection, Item = {
return UICollectionViewDiffableDataSourceSection, Item(collectionView: collectionView) { collectionView, indexPath, item in
print("data source reloading cell", item, indexPath)
let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: "cell",
for: indexPath
) as! Cell
cell.item = item
return cell
}
}()
private lazy var listLayout: UICollectionViewCompositionalLayout = {
let conf = UICollectionLayoutListConfiguration(appearance: .plain)
return UICollectionViewCompositionalLayout.list(using: conf)
}()
private lazy var regularLayout: UICollectionViewCompositionalLayout = {
let item = NSCollectionLayoutItem(
layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
)
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50)),
subitem: item,
count: 1
)
let section = NSCollectionLayoutSection(group: group)
return UICollectionViewCompositionalLayout(section: section)
}()
private lazy var collectionView: UICollectionView = {
let view = UICollectionView(frame: .zero, collectionViewLayout: regularLayout)
view.register(Cell.self, forCellWithReuseIdentifier: "cell")
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .systemBackground
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
var snapshot = NSDiffableDataSourceSnapshotSection, Item()
snapshot.appendSections([.main])
snapshot.appendItems((0 .. 100).map { .init(id: "\($0)") })
dataSource.apply(snapshot, animatingDifferences: false)
Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { _ in
print("\n\nDelayed Reloading")
var snapshot = self.dataSource.snapshot()
self.dataSource.apply(snapshot, animatingDifferences: true)
}
}
class Cell: UICollectionViewCell {
var item: Item? {
didSet {
label.text = item?.id
}
}
private(set) lazy var label: UILabel = {
let view = UILabel()
view.font = .systemFont(ofSize: 48, weight: .semibold)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
print("cell inited")
contentView.addSubview(label)
NSLayoutConstraint.activate([
label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12),
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -12),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
Output
Xcode 12.5
iPhone 11 device (iOS 14.5.1)
Delayed Reloading
data source reloading cell Item(id: "2") [0, 2]
data source reloading cell Item(id: "4") [0, 4]
data source reloading cell Item(id: "6") [0, 6]
data source reloading cell Item(id: "8") [0, 8]
data source reloading cell Item(id: "10") [0, 10]
data source reloading cell Item(id: "12") [0, 12]
data source reloading cell Item(id: "14") [0, 14]
data source reloading cell Item(id: "1") [0, 1]
data source reloading cell Item(id: "3") [0, 3]
data source reloading cell Item(id: "5") [0, 5]
data source reloading cell Item(id: "7") [0, 7]
data source reloading cell Item(id: "9") [0, 9]
data source reloading cell Item(id: "11") [0, 11]
data source reloading cell Item(id: "13") [0, 13]
data source reloading cell Item(id: "15") [0, 15]
data source reloading cell Item(id: "0") [0, 0]
data source reloading cell Item(id: "11") [0, 11]
Is this an expected behavior?
I've also run the same test on UITableView, which is much more reasonable. Only some off-screen cells are reloaded.