Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> iOS

วิธีใช้ UICollectionView ใน Swift

UICollectionView แสดงข้อมูลแบบ Grid/Custom Layout ใช้ DataSource, Delegate, FlowLayout

Setup แบบโปรแกรม


class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupCollectionView()
    }
    
    func setupCollectionView() {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 100, height: 100)
        layout.minimumInteritemSpacing = 10
        layout.minimumLineSpacing = 10
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        layout.scrollDirection = .vertical
        
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
        collectionView.backgroundColor = .systemBackground
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView.register(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "Header")
        
        view.addSubview(collectionView)
    }
    
    // DataSource
    func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 20 }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        cell.backgroundColor = .systemBlue
        cell.layer.cornerRadius = 8
        
        // Add Label
        if cell.contentView.subviews.isEmpty {
            let label = UILabel(frame: cell.contentView.bounds)
            label.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            label.textAlignment = .center
            label.textColor = .white
            label.font = .boldSystemFont(ofSize: 16)
            label.tag = 100
            cell.contentView.addSubview(label)
        }
        (cell.contentView.viewWithTag(100) as? UILabel)?.text = "\(indexPath.item)"
        
        return cell
    }
    
    // Delegate - Selection
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("Selected: \(indexPath.item)")
    }
    
    // FlowLayout Delegate - Dynamic Size
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = (collectionView.bounds.width - 30) / 2 // 2 columns
        return CGSize(width: width, height: width)
    }
}

Compositional Layout (iOS 13+ แนะนำ)


func createLayout() -> UICollectionViewLayout {
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
    
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.5))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    
    let section = NSCollectionLayoutSection(group: group)
    section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
    
    return UICollectionViewCompositionalLayout(section: section)
}

// ใช้งาน
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())

Diffable Data Source (iOS 13+)


typealias DataSource = UICollectionViewDiffableDataSource
typealias Snapshot = NSDiffableDataSourceSnapshot

enum Section { case main }
struct Item: Hashable { let id = UUID(); let title: String }

lazy var dataSource = DataSource(collectionView: collectionView) { cv, indexPath, item in
    let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
    cell.backgroundColor = .systemBlue
    (cell.contentView.viewWithTag(100) as? UILabel)?.text = item.title
    return cell
}

func applySnapshot(items: [Item]) {
    var snapshot = Snapshot()
    snapshot.appendSections([.main])
    snapshot.appendItems(items)
    dataSource.apply(snapshot, animatingDifferences: true)
}

Cell Registration (iOS 14+)


let cellRegistration = UICollectionView.CellRegistration { cell, indexPath, item in
    var config = UIListContentConfiguration.cell()
    config.text = item.title
    config.textProperties.color = .white
    config.textProperties.font = .boldSystemFont(ofSize: 16)
    cell.contentConfiguration = config
    cell.backgroundConfiguration = .clear()
    cell.layer.cornerRadius = 8
}

dataSource = DataSource(collectionView: collectionView) { cv, indexPath, item in
    cv.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}