Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- clean architecture
- Human interface guide
- MVVM
- uiscrollview
- Clean Code
- SWIFT
- ribs
- rxswift
- Protocol
- Refactoring
- Xcode
- ios
- 리팩토링
- Observable
- swift documentation
- UITextView
- collectionview
- 리펙터링
- RxCocoa
- HIG
- swiftUI
- 애니메이션
- combine
- 리펙토링
- map
- uitableview
- 클린 코드
- UICollectionView
- 스위프트
- tableView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 2. UICollectionViewFlowLayout 사용 방법 - 격자, 그리드 뷰 (grid view) 본문
iOS 응용 (swift)
[iOS - swift] 2. UICollectionViewFlowLayout 사용 방법 - 격자, 그리드 뷰 (grid view)
jake-kim 2022. 5. 17. 23:411. UICollectionViewFlowLayout 사용 방법 - 수평 스크롤 뷰 (horizontal scroll view)
2. UICollectionViewFlowLayout 사용 방법 - 격자, 그리드 뷰 (grid view)
FlowLayout을 사용하면 columns 수도 손쉽게 변경 가능
구현 아이디어
- 셀의 레이아웃을 결정하는 곳은 델리게이트임을 알고 (UICollectinoViewDelegateFlowLayout) 여기서 셀의 크기를 결정하도록 설정
- 위 델리게이트 중 sizeForItemAt 메소드에서 collectionView의 width값을 가져와서 너비에 관한 적절한 크기를 계산해서 셀의 크기를 결정해주면 grid cell 완성
- 셀의 크기 계산
- collectionView.bounds.width값에서 좌우 contentInset값과 중간에 있는 cell space 값을 뺀값이 전체 width가 될 값
- 이 전체 width에서 사용하고 싶은 columns 수만큼 나누어주면 그만큼 셀의 크기가 정해지게 되어 grid형태 레이아웃 구현 완료
UICollectionViewFlowLayout 서브클래싱 정의
- cell spacing과 scrollDirection을 디폴트로 설정
- 사용하는쪽의 sizeForItemAt 델리게이트 메소드에서 property에 접근하여 numberOfColumns등의 값을 얻기 위해 프로퍼티 선언
import UIKit
class GridCollectionViewFlowLayout: UICollectionViewFlowLayout {
var numberOfColumns = 1
var cellSpacing = 0.0 {
didSet {
self.minimumLineSpacing = self.cellSpacing
self.minimumInteritemSpacing = self.cellSpacing
}
}
override init() {
super.init()
self.scrollDirection = .vertical
}
required init?(coder: NSCoder) {
fatalError()
}
}
커스텀 셀
- UICollectionViewCell을 서브클래싱하고 있고 단순히 이미지 뷰 하나를 들고있는 셀
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),
])
}
override func prepareForReuse() {
super.prepareForReuse()
self.prepare(image: nil)
}
func prepare(image: UIImage?) {
self.imageView.image = image
}
}
collectionView 사용하는 쪽
- 데이타 소스 준비
import UIKit
class ViewController: UIViewController {
private var dataSource = getSampleImages()
}
func getSampleImages() -> [UIImage?] {
(1...100).map { _ in return UIImage(named: "dog") }
}
- flowLayout 선언
- 2개의 columns를 갖도록 설정 (밑에 sizeForItemAt 델리게이트 메소드에서 해당 값 사용할 예정)
import UIKit
class ViewController: UIViewController {
private let gridFlowLayout: GridCollectionViewFlowLayout = {
let layout = GridCollectionViewFlowLayout()
layout.cellSpacing = 8
layout.numberOfColumns = 2
return layout
}()
private var dataSource = getSampleImages()
}
- collectionView 프로퍼티
private lazy var collectionView: UICollectionView = {
let view = UICollectionView(frame: .zero, collectionViewLayout: self.gridFlowLayout)
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
}()
- 레이아웃 정의, 핵심인 delegate 선언
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.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
])
self.collectionView.dataSource = self
self.collectionView.delegate = self
}
(dataSource는 생략)
- UICollectionViewDelegateFlowLayout의 sizeForItemAt 메소드에서 셀의 사이즈를 계산
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
}
}
- 먼저 flowLayout 인스턴스를 다운캐스팅 (위에서 선언한 numberOfColumns 값을 사용하기 위함)
guard
let flowLayout = collectionViewLayout as? GridCollectionViewFlowLayout,
flowLayout.numberOfColumns > 0
else { fatalError() }
- cell의 width값을 계산
// cell들의 width값 (내부 spacing 존재)
let widthOfCells = collectionView.bounds.width - (collectionView.contentInset.left + collectionView.contentInset.right)
// spacing 값
let widthOfSpacing = CGFloat(flowLayout.numberOfColumns - 1) * flowLayout.cellSpacing
// cell하나의 width = cell들의 width값에서 spacing값을 뺀것
let width = (widthOfCells - widthOfSpacing) / CGFloat(flowLayout.numberOfColumns)
return CGSize(width: width, height: width)
* 전체 코드: https://github.com/JK0369/ExGridView
'iOS 응용 (swift)' 카테고리의 다른 글
Comments