カルボナーラ街道

計測と観察

orthogonalScrollingBehaviorを試す

趣味プログラミングは勢いで書け!

開発環境

> xcodebuild -version
Xcode 14.0
Build version 14A5229c

Xcodeはbetaだが本記事の内容はiOS16未満のAPIを使用。

モチベーション

orthogonalScrollingBehavior を使ったことがなかったので書いてみる。

できたもの

www.youtube.com

コード

import UIKit

final class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView! {
        didSet {
            collectionView.dataSource = self
            collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "customCell")
            collectionView.collectionViewLayout = createLayout()
        }
    }
    
    private func createLayout() -> UICollectionViewCompositionalLayout {
        let horizontalMargin: CGFloat = 20
        let verticalMargin: CGFloat = 10
        let interItemSpacing: CGFloat = 4
        let horizontalItemCount: CGFloat = 3
        let screenWidth = UIScreen.main.bounds.width
        
        let availableWidth = screenWidth - horizontalMargin * 2 - (horizontalItemCount - 1) * interItemSpacing
        let itemLength = availableWidth / horizontalItemCount
        
        // Item
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .absolute(itemLength),
            heightDimension: .absolute(itemLength)
        )
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        
        // Group
        let groupSize = NSCollectionLayoutSize(
            widthDimension: .absolute(screenWidth),
            heightDimension: .absolute(itemLength + verticalMargin * 2)
        )
        let group = NSCollectionLayoutGroup.horizontal(
            layoutSize: groupSize,
            subitems: [item]
        )
        group.interItemSpacing = .fixed(interItemSpacing)
        group.contentInsets = .init(
            top: 0,
            leading: horizontalMargin,
            bottom: 0,
            trailing: horizontalMargin
        )
        
        // Section
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets = NSDirectionalEdgeInsets(
            top: verticalMargin,
            leading: 0,
            bottom: verticalMargin,
            trailing: 0
        )
        section.orthogonalScrollingBehavior = .groupPaging
        
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
    }
}

extension ViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 9
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(
            withReuseIdentifier: "customCell",
            for: indexPath
        ) as? CustomCollectionViewCell else {
            return UICollectionViewCell()
        }
        
        cell.backgroundColor = {
            switch indexPath.row / 3 {
            case 0:
                return .systemRed
            case 1:
                return .systemBlue
            case 2:
                return .systemGreen
            default:
                return nil
            }
        }()
        return cell
    }
}

参考