Here is my problem:
1. ScrollViewDelegate does not get called once UICollectionView implements compositionalLayout.
With flowLayout and UICollectionViewDataSource the scrollView delegates get called. Once I implement the diffable datasource and CompositionalLayout the scrollView delegates don't get called anymore.
2. collectionView.decelerationRate = .fast gets ignored when implementing CompositionalLayout
My understanding is that UICollectionViewDelegate should call UIScrollViewDelegate, I have looked wide and far but no luck. Can someone point me out what am I missing? Am I integrating compositionalLayout wrong?
here is my code:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UIScrollViewDelegate {
enum Section {
case weekdayHeader
}
@IBOutlet weak var collectionView: UICollectionView!
let weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday","Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
var weekdaysArr = [Weekdays]()
var dataSource: UICollectionViewDiffableDataSource<Section, Weekdays>! = nil
private let cellReuseIdentifier = "myCell"
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
self.collectionView.register(UINib(nibName: "MyCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: cellReuseIdentifier)
self.collectionView.decelerationRate = .normal
configureCollectionView()
configureDataSource()
configureWeekdays()
updateCollectionView()
// Do any additional setup after loading the view.
}
func configureCollectionView(){
self.collectionView.delegate = self
self.collectionView.collectionViewLayout = generateLayout()
}
func generateLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .estimated(10),
heightDimension: .fractionalHeight(1))
let weekdayItem = NSCollectionLayoutItem(layoutSize: itemSize)
// weekdayItem.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 50)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.3),
heightDimension: .fractionalHeight(1.0))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [weekdayItem])
// let spacing = CGFloat(10)
// group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = CGFloat(20)
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 500)
section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
func configureDataSource() {
dataSource = UICollectionViewDiffableDataSource
<Section, Weekdays>(collectionView: collectionView)
{ (collectionView: UICollectionView, indexPath: IndexPath, weekday: Weekdays) -> UICollectionViewCell? in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellReuseIdentifier, for: indexPath) as? MyCollectionViewCell else {
fatalError("Cannot create a new cell") }
cell.titleLabel.text = weekday.name
print("weekday.name = (weekday.name)")
return cell
}
// let snapshot = snapshotForCurrentState()
// dataSource.apply(snapshot, animatingDifferences: false)
}
func configureWeekdays(){
weekdaysArr.append(Weekdays(name: "Monday"))
weekdaysArr.append(Weekdays(name: "Tuesday"))
weekdaysArr.append(Weekdays(name: "Wednesday"))
weekdaysArr.append(Weekdays(name: "Thursday"))
weekdaysArr.append(Weekdays(name: "Friday"))
weekdaysArr.append(Weekdays(name: "Saturday"))
weekdaysArr.append(Weekdays(name: "Sunday"))
}
func updateCollectionView(){
var snapshot = NSDiffableDataSourceSnapshot<Section, Weekdays>()
snapshot.appendSections([.weekdayHeader])
snapshot.appendItems(weekdaysArr, toSection: .weekdayHeader)
dataSource.apply(snapshot, animatingDifferences: false)
}
//MARK: Scroll View Delegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("ScrollView decel rate: (scrollView.decelerationRate)")
}
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
print("Begin")
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
print("End")
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
print("END")
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Did select a cell here")
}
}
struct Weekdays: Hashable {
let identifier: UUID = UUID()
let name: String
func hash(into hasher: inout Hasher){
return hasher.combine(identifier)
}
static func == (lhs: Weekdays, rhs: Weekdays) -> Bool {
return lhs.identifier == rhs.identifier
}
}
Thank you
Edit: Updated Code -
Edit: Comparing against Apples sample code from WWDC I found out this behaviour.
If I use the sample codes Grid layout
func gridLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalWidth(0.2))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,
subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
When having only 7 Items the Scroll Delegate methods never get called.
I can still scroll though and the expected behavior should be that the scroll delegate methods do get called as I have vertical bounce.
When having about 40 items though and the content is obviously beyond the screen size the scroll delegate does get called.
Now interestingly when loading my own layout:
func generateLayout() -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(
widthDimension: .estimated(10),
heightDimension: .fractionalHeight(1))
let weekdayItem = NSCollectionLayoutItem(layoutSize: itemSize)
// weekdayItem.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 50, bottom: 5, trailing: 50)
let groupSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(0.3),
heightDimension: .fractionalHeight(1.0))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [weekdayItem])
// let spacing = CGFloat(10)
// group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = CGFloat(20)
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 500)
section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
The Scroll delegates never get called. Even with 40+ Items.
Any ideas as to how to force UICollectionView to communicate with its ScrollViewDelegates?
See Question&Answers more detail:
os