관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 1. UICollectionViewFlowLayout 사용 방법 - 수평 스크롤 뷰 (horizontal scroll view) 본문

iOS 응용 (swift)

[iOS - swift] 1. UICollectionViewFlowLayout 사용 방법 - 수평 스크롤 뷰 (horizontal scroll view)

jake-kim 2022. 5. 16. 23:56

1. UICollectionViewFlowLayout 사용 방법 - 수평 스크롤 뷰 (horizontal scroll view)

2. UICollectionViewFlowLayout 사용 방법 - 격자, 그리드 뷰 (grid view)

UICollectionViewFlowLayout으로 구현한 수평 스크롤 뷰

cf)UICollectionViewCompositionalLayout를 이용한 방법은 이 포스팅 글 참고

구현 아이디어

  • 커스텀 셀
    • 셀의 CGSize 크기는 collectionView를 사용하는쪽에서 정해질 것을 인지하고 cell에서는 autolayout 작성 시 크기를 생각하지 않고 레이아웃만 집중
  • collectionView 사용하는 곳
    • flowLayout인스턴스의 scrollDirection 방향을 horizontal로 설정
    • flowLayout인스턴스의 cellSize 적용
    • autolayout 구현 시, collectionView의 height값이 cell 사이즈 한개보다 큰 경우, 셀이 아래처럼 하단으로 먼저 나열되므로 주의

collectionView의 height값이 커서 여러줄이 있는 UI로 된 것

커스텀 셀 구현

  • 셀의 CGSize 크기는 collectionView를 사용하는쪽에서 정해질 것을 인지하고 cell에서는 autolayout 작성 시 크기를 생각하지 않고 레이아웃만 집중
import UIKit

final class MyCell: UICollectionViewCell {
  static let id = "MyCell"
  
}
  • 이미지 뷰가 하나 있는 셀
  // MARK: UI
  private let imageView: UIImageView = {
    let view = UIImageView()
    view.contentMode = .scaleAspectFill
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }()
  
  // MARK: Initializer
  @available(*, unavailable)
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    
    self.contentView.addSubview(self.imageView)
    NSLayoutConstraint.activate([
      self.imageView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor),
      self.imageView.rightAnchor.constraint(equalTo: self.contentView.rightAnchor),
      self.imageView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
      self.imageView.topAnchor.constraint(equalTo: self.contentView.topAnchor),
    ])
  }
  • prepare 정의
  override func prepareForReuse() {
    super.prepareForReuse()
    
    self.prepare(image: nil)
  }
  
  func prepare(image: UIImage?) {
    self.imageView.image = image
  }

UICollectionView 사용하는쪽 구현

  • 샘플 데이터 준비
// ViewController.swift

class ViewController: UIViewController {
  private var dataSource = getSampleImages() 
}

func getSampleImages() -> [UIImage?] {
  (1...100).map { _ in return UIImage(named: "dog") }
}
  • flowLayout
    • flowLayout인스턴스의 scrollDirection 방향을 horizontal로 설정
    • flowLayout인스턴스의 cellSize 적용
  private let flowLayout: UICollectionViewFlowLayout = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
//    layout.minimumLineSpacing = 8.0
    layout.minimumInteritemSpacing = 8.0
    layout.itemSize = CGSize(width: 100, height: 100)
    return layout
  }()
  • collectionView 인스턴스
  private lazy var collectionView: UICollectionView = {
    let view = UICollectionView(frame: .zero, collectionViewLayout: self.flowLayout)
    view.isScrollEnabled = true
    view.showsHorizontalScrollIndicator = false
    view.showsVerticalScrollIndicator = true
//    view.scrollIndicatorInsets = UIEdgeInsets(top: -2, left: 0, bottom: 0, right: 4)
    view.contentInset = .zero
    view.backgroundColor = .clear
    view.clipsToBounds = true
    view.register(MyCell.self, forCellWithReuseIdentifier: "MyCell")
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
  }()
  • collectionView의 autolayout 구현 시, 한줄 수평 스크롤뷰를 만들것이므로, height값 지정
override func viewDidLoad() {
  super.viewDidLoad()
  
  self.view.addSubview(self.collectionView)

  NSLayoutConstraint.activate([
    self.collectionView.leftAnchor.constraint(equalTo: self.view.leftAnchor),
    self.collectionView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
    self.collectionView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 120),
    self.collectionView.heightAnchor.constraint(equalToConstant: 500),
  ])
  
  self.collectionView.dataSource = self
}
  • dataSource에서 데이터 할당
extension ViewController: UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    self.dataSource.count
  }
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MyCell.id, for: indexPath) as! MyCell
    cell.prepare(image: self.dataSource[indexPath.item])
    return cell
  }
}

* 전체 코드: https://github.com/JK0369/ExHorizontalScrollView

Comments