✅ 이번 시간에는 rx 적용 및 컬렉션 뷰 Flow의 값을 줄 때, 상하 간격도 주는 것을 함께 해보았다.
결과와 코드를 보면서 함께하자.
⭐️ 진짜 핵심은 제일 아래쪽에 위치하고 있습니다:)
✅ 코드리뷰
//
// File.swift
// SnapKit_practice
//
// Created by Hamlit Jason on 2021/08/22.
//
import UIKit
import RxDataSources
import RxSwift
import RxCocoa
import CoreLocation
import Foundation
import Differentiator
import Then
// Cell
class MyCollectionViewCell3 : UICollectionViewCell {
static let identifier = "cell3"
var img = UIImageView().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.image = UIImage(named: "testImage")
}
var label = UILabel().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.text = "상어상어"
}
override init(frame: CGRect) {
super.init(frame: frame)
self.cellSetting()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func cellSetting() {
self.backgroundColor = .gray
self.addSubview(img)
self.addSubview(label)
img.contentMode = .scaleToFill
img.snp.makeConstraints {
$0.leading.top.trailing.equalTo(0)
$0.bottom.equalTo(-20)
}
label.snp.makeConstraints {
$0.leading.bottom.trailing.equalTo(0)
$0.top.equalTo(img.snp.bottom)
}
}
}
class ViewController10 : UIViewController {
var array = ["first","second","third","fourth","fifth","6","7","8","9","10","11","12"]
var collectionView : UICollectionView = {
var layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.scrollDirection = .vertical
layout.sectionInset = .zero
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .green
return cv
}()
let sectionInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
override func viewDidLoad() {
super.viewDidLoad()
let data = Observable<[String]>.of(self.array)
view.addSubview(collectionView)
collectionView.delegate = self // rx쓰더라도 이거 꼭 연결해야해
// collectionView.dataSource = self
autoLayout()
collectionView.register(MyCollectionViewCell3.self, forCellWithReuseIdentifier: MyCollectionViewCell3.identifier)
data.asObservable()
.bind(to: collectionView.rx
.items(
cellIdentifier: MyCollectionViewCell3.identifier,
cellType: MyCollectionViewCell3.self)
) { index, recommend, cell in
cell.img.image = UIImage(named: "testImage")
cell.label.text = "index \(index)"
}
}
}
extension ViewController10 : UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.width
let height = collectionView.bounds.height
let itemsPerRow: CGFloat = 3 // 최초 화면에 보여져야하는 row rottn
let widthPadding = sectionInsets.left * (itemsPerRow + 1)
var itemsPerColumn: CGFloat = 4 // 최초 화면에 보여져야하는 columns 갯수
itemsPerColumn = ceil(itemsPerColumn)
print(itemsPerColumn)
let heightPadding = sectionInsets.top * (itemsPerColumn + 1)
let cellWidth = (width - widthPadding) / itemsPerRow
let cellHeight = (height - heightPadding) / itemsPerColumn
return CGSize(width: cellWidth, height: cellHeight)
}
// case A
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
// case B
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
extension ViewController10 {
private func autoLayout() {
collectionView.snp.makeConstraints {
$0.edges.equalTo(view.safeAreaLayoutGuide)
.inset(UIEdgeInsets(top: 0, left: 0, bottom: 200, right: 0))
}
}
}
위에 코드를 보면 case A와 case B를 적어뒀는데 아래 코드를 보면서 각 부분이 주석처리 되었을 때 달라지는 변화를 관찰해보자.
왼쪽 : case A만 주석처리
가운데 : case A,B 모두 주석처리
오른쪽 : case B만 주석처리
코드의 결과를 보면
case B는 상하의 간격을 조절하는 코드다
case A는 inset으로 뷰의 가장자리에서 거리를 조절하는 코드이다.
❗️✅ 위의 코드의 치명적인 단점
위의 코드에서는
itemsPerRow 와 itemsPerColumn를 하드 코딩하게 주고 있다.
이런 경우에 어떤 문제가 발생하냐면 우리가 초록생 영역에 우선적으로 보여져야하는 Row와 Coloumn의 갯수가 정해져 버리게 된다.
물론 스크롤은 가능하나 화면에 딱 맞게 보여져야 함으로 컬렉션 뷰의 Height에 따라서 컬렉션 뷰 셀의 비율을 우리가 원하는대로 가져가지 못하는 경우가 생길 수 있다.
아래의 사진을 보면 문제점을 정확하게 짚어낼 수 있다.
🟠 만약 우리가 위의 코드로 레이아웃을 사용하고자 한다면, 더 세심한 주의가 필요하다고 생각된다.
✅ 그렇다면 조금 더 common하게 사용할 방법은 없을까?
있지 당연히!! 지금 여기부터가 정말정말 핵심 부분이니까 꼭 집중해서 보기 바란다.
//
// File.swift
// SnapKit_practice
//
// Created by Hamlit Jason on 2021/08/22.
//
import UIKit
import RxDataSources
import RxSwift
import RxCocoa
import CoreLocation
import Foundation
import Differentiator
import Then
// Cell
class MyCollectionViewCell3 : UICollectionViewCell {
static let identifier = "cell3"
var img = UIImageView().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.image = UIImage(named: "testImage")
}
var label = UILabel().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.text = "상어상어"
}
override init(frame: CGRect) {
super.init(frame: frame)
self.cellSetting()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func cellSetting() {
self.backgroundColor = .gray
self.addSubview(img)
self.addSubview(label)
img.contentMode = .scaleToFill
img.snp.makeConstraints {
$0.leading.top.trailing.equalTo(0)
$0.bottom.equalTo(-20)
}
label.snp.makeConstraints {
$0.leading.bottom.trailing.equalTo(0)
$0.top.equalTo(img.snp.bottom)
}
}
}
class ViewController10 : UIViewController {
var array = ["first","second","third","fourth","fifth","6","7","8","9","10","11","12"]
var collectionView : UICollectionView = {
var layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 0
layout.scrollDirection = .vertical
layout.sectionInset = .zero
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .green
return cv
}()
let sectionInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
override func viewDidLoad() {
super.viewDidLoad()
let data = Observable<[String]>.of(self.array)
view.addSubview(collectionView)
collectionView.delegate = self // rx쓰더라도 이거 꼭 연결해야해
// collectionView.dataSource = self
autoLayout()
collectionView.register(MyCollectionViewCell3.self, forCellWithReuseIdentifier: MyCollectionViewCell3.identifier)
data.asObservable()
.bind(to: collectionView.rx
.items(
cellIdentifier: MyCollectionViewCell3.identifier,
cellType: MyCollectionViewCell3.self)
) { index, recommend, cell in
cell.img.image = UIImage(named: "testImage")
cell.label.text = "index \(index)"
}
}
}
extension ViewController10 : UICollectionViewDelegateFlowLayout {
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 - 20 - itemSpacing * 2) / 3
//let height : CGFloat = width * 10/7 + textAreaHeight
return CGSize(width: width, height: width)
}
// case A
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
// case B
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
extension ViewController10 {
private func autoLayout() {
collectionView.snp.makeConstraints {
$0.edges.equalTo(view.safeAreaLayoutGuide)
.inset(UIEdgeInsets(top: 0, left: 0, bottom: 200, right: 0))
}
}
}
위의 코드를 보면 UICollectionViewDelegateFlowLayout 부분만 달라진 것을 확인할 수 있다.
width의 값을 설정할때 -20을 하드코딩으로 처리한 이유는 sectionInsets으로 인하며 좌우 공간이 20만큼 빠지기 때문에 그냥 하드코딩으로 넣어주었다.
이렇게 설정하면 정말정말 예쁘게 컬렉션 뷰를 활용할 수 있다!
'apple > iOS' 카테고리의 다른 글
[iOS] TTGTagCollectionView에 대해서 알아보자. (0) | 2022.02.17 |
---|---|
iOS Snapkit 나만의 정리 모음 (5) | 2021.08.25 |
iOS Snapkit 09 | CollectionView 코드로 구성하는 법 02 (0) | 2021.08.22 |
iOS Snapkit 08 | CollectionView 코드로 구성하는 법 01 (0) | 2021.08.22 |
iOS SnapKit 05 | iOS tableView를 코드로 구성하는 법 03 (0) | 2021.08.19 |