본문 바로가기

ComputerScience/ios App(Storyboard)

ios - 16 CollectionView

728x90

1 CollectionView

- tableViewCell로 tableView를 구성하면 아래 그림 처럼 한 행을 cell로 하여 여러 항목들을 리스트로 나열할 수 있었다.

- collectionView를 사용하면 아래 처럼 한 행에 여러 항목들을 표현할 수 있다.

- collectionViewCell로 collectionView를 구성할 것이다.

- 여러 형태의 레이아웃이 가능하기 때문에 tableView와는 다르게 layout을 관리하는 UICollectionViewLayout 객체가 존재한다.

- customizing을 위해서는 위 요소들을 상속하여 다양한 형태로 변형하면 된다.

 

- 원피스 현상금앱의 현상금 정보들을 tableView 말고 collectionView로 나타내보자

- 기존 tableView를 제거하고 collectionView를 추가한다. 

- collectionViewCell을 알맞은 크기로 조정한다.

- collectionViewCell을 UI Component로 채운다.

- collectionView와 해당하는 viewController를 연결한다. datasource와 delegate항목을 연결해줘야 한다.

2 코드작성

import UIKit

class BountyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    
    let viewModel = BountyViewModel()

- CollectionView를 위한 protocol들을 상속하여 구현조건을 충족시켜야한다.

- 하나씩 어떤 프로토콜인지 살펴보자.

    // UICollectionViewDataSource
    // 몇개를 보여줄까요?
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel.numOfBountyInfoList
    }

- collectionView안에 몇개의 collectionViewCell을 넣을 것인지 알려주어야 한다.

// 셀은 어떻게 표현할거야?
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "GridCell", for: indexPath) as? GridCell else {
            return UICollectionViewCell()
        }
        
        let info = viewModel.bountyInfo(at: indexPath.row)
        cell.updateUI(info: info)
        return cell
    }

- 각 셀은 어떻게 생겼는지 알려주어야 한다.

- GridCell이라는 클래스의 형태로 cell을 그릴 것이다.

- dequeueReusableCell은 이미 화면에 그린 셀을 다시 그릴때 재사용하겠다는 뜻이고 이를 위해서 해당 셀을 알아볼 수 있도록 GridCell이라는 식별자를 사용하겠다.

- GirdCell을 클릭하여 custom class와 재사용을 위한 identifier를 적어주자.

- 그럼 마지막으로 ui 컴포넌트들과 GridCell의 프로퍼티들의 outlet을 연결하자.

    // UICollectionViewDelegateFlowLayout
    // cell size??
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        let itemSpacing: CGFloat = 10
        let textAreaHeight: CGFloat = 65
        
        let width: CGFloat = (collectionView.bounds.width - itemSpacing)/2
        let height: CGFloat = width * 10/7 + textAreaHeight
        return CGSize(width: width, height: height)
    }

- cell의 크기도 정해야한다.

- collectionView.bounds로 컬렉션 뷰의 크기를 가져올 수 있다. width를 알고 싶다면 collectionView.bounds.width가 된다.

- 셀의 크기를 CGSize 타입으로 반환해야 한다.

// UICollectionViewDelegate
    // 셀이 클릭되었을때 어쩔거야?
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        performSegue(withIdentifier: "showDetail", sender: indexPath.item)
    }

- 마지막은 셀이 클릭되었을 때 동작을 정의한다.

- showDetail이라는 segue를 수행할 것이고 어떤 셀이 눌렸는지 indexPath.item를 보내준다.

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            let vc = segue.destination as? DetailViewController
            if let index = sender as? Int {
                let bountyInfo = viewModel.bountyInfo(at: index)
                vc?.viewModel.update(model: bountyInfo)
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

class GridCell: UICollectionViewCell {
    @IBOutlet weak var imgView: UIImageView!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var bountyLabel: UILabel!
    
    func updateUI(info: BountyInfo) {
        imgView.image = info.image
        nameLabel.text = info.name
        bountyLabel.text = "\(info.bounty)"
    }
}

- 다음 스크린으로 segueway를 통해 데이터를 넘겨주기 위한 준비 동작과 GridCell의 코드이다.

2 실행결과

728x90
반응형

'ComputerScience > ios App(Storyboard)' 카테고리의 다른 글

ios - 18 Animation with ViewProperties  (0) 2021.08.03
ios - 17 Animation with contraints  (0) 2021.08.03
ios - 15 Design Pattern  (0) 2021.08.02
ios - 14 Segue  (0) 2021.07.28
ios - 13 Custom Cell  (0) 2021.07.28