Toroidal effect (infinite Loop) in sections of uiCollectionView

I have a mosaic of cells with interleaved movement, but I have not achieved a toroidal effect so that the cells appear again.

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    private var timer: Timer?
    private var sections: Int = 5
    private let cellSizes: [CGSize] = [
        CGSize(width: 150, height: 200),
        CGSize(width: 200, height: 150),
        CGSize(width: 180, height: 180),
        CGSize(width: 150, height: 200),
        CGSize(width: 200, height: 150),
        CGSize(width: 180, height: 180)
    ]
    private var scrollDirections: [CGFloat] = []
    private var sectionOffsets: [CGFloat] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
        setupScrollDirections()
        startAutoScrolling()
    }
    
    private func setupCollectionView() {
        collectionView.dataSource = self
        collectionView.collectionViewLayout = createLayout()
        collectionView.isPagingEnabled = false
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.showsVerticalScrollIndicator = false
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
    }
    
    private func setupScrollDirections() {
        for index in 0..<sections {
            scrollDirections.append(index % 2 == 0 ? 1.0 : -1.0)
            sectionOffsets.append(0.0)
        }
    }
    
    private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { sectionIndex, _ in

            let itemSize = NSCollectionLayoutSize(
                widthDimension: .absolute(self.cellSizes[sectionIndex % self.cellSizes.count].width),
                heightDimension: .absolute(self.cellSizes[sectionIndex % self.cellSizes.count].height)
            )
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
            
            let groupSize = NSCollectionLayoutSize(
                widthDimension: .estimated(800),
                heightDimension: .absolute(self.cellSizes[sectionIndex % self.cellSizes.count].height + 20)
            )
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            group.interItemSpacing = .fixed(10)
            
            let section = NSCollectionLayoutSection(group: group)
            section.orthogonalScrollingBehavior = .continuous
            section.interGroupSpacing = 10
            return section
        }
        return layout
    }

    private func startAutoScrolling() {
        timer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(performAutoScroll), userInfo: nil, repeats: true)
    }
    
    @objc private func performAutoScroll() {
        for section in 0..<sections {
            let direction = scrollDirections[section]
            sectionOffsets[section] += 1.0 * direction
            
            for cell in collectionView.visibleCells {
                if let indexPath = collectionView.indexPath(for: cell), indexPath.section == section {
                    cell.transform = CGAffineTransform(translationX: sectionOffsets[section], y: 0)
                    let maxOffset = collectionView.contentSize.width
                    if abs(sectionOffsets[section]) > maxOffset {
                        sectionOffsets[section] = 0
                    }
                }
            }
        }
    }
    
    deinit {
        timer?.invalidate()
    }
}

extension ViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return sections
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        cell.backgroundColor = randomColor()
        cell.layer.cornerRadius = 8
        return cell
    }
    
    private func randomColor() -> UIColor {
        return UIColor(red: .random(in: 0...1),
                       green: .random(in: 0...1),
                       blue: .random(in: 0...1),
                       alpha: 1.0)
    }
}

Upvotes: 0

Views: 27

Answers (0)

Related Questions