관리 메뉴

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

[iOS - swift] 2. 스크롤되는 PagerView 구현 방법 - 하단 PagerView 본문

UI 컴포넌트 (swift)

[iOS - swift] 2. 스크롤되는 PagerView 구현 방법 - 하단 PagerView

jake-kim 2023. 6. 19. 22:41

1. 스크롤되는 PagerView 구현 방법 - 상단 TabView 구현하기

2. 스크롤되는 PagerView 구현 방법 - 하단 PagerView 구현하기 v

3. 스크롤되는 PagerView 구현 방법 - Tab과 Pager 스크롤 싱크 맞추기

구현한 PagerView

PagerView 형태

  • 상단에는 TabView
    • UIScrollView안에 UIStackView를 넣어서 구현하고 각 tap 이벤트는 뷰의 tag를 사용하면 인덱스를 구할 수 있음
  • 하단에는 PagerView
    • 페이지 기능을 쉽게 사용하기 위해서 UICollectionView를 사용하여 구현
    • 주의) UIPageViewController를 사용하지 않음 - UIPageViewController안에 내장된 UIScrollView의 형태는 내부 content 크기만큼 있는게 아닌 페이지의 크기만큼만 존재하므로, 스크롤 했을 때 제대로된 contentOffset을 가져오기가 힘듦

pagerView 구현 아이디어

  • CollectionView의 isPagingEnabled를 true로하여 구현
  • UICollectionViewFlowLayout를 사용하고, 셀의 width값은 현재 화면의 크기만큼 설정
  • 셀 크기 계산 방법?
    • UICollectionViewDelegateFlowLayout의 sizeForItemAt 델리게이트에서 셀 크기를 리턴할수 있는데 이 때 pagerView의 frame을 리턴하도록 구현
    • (사용하는쪽에서 화면 크기 너비와 동일하도록 autolayout으로 설정해놓으면, 런타임 때 sizeForItemAt 델리게이트에서 너비를 리턴)

pagerView 구현

 

  • 필요한 Cell 구현
    • UILabel이 중앙에 하나 있는 셀
import UIKit
import Then
import SnapKit

// MARK: - PagerCell
final class PagerCell: UICollectionViewCell {
    // MARK: UI
    private let titleLabel = UILabel().then {
        $0.numberOfLines = 0
        $0.font = .systemFont(ofSize: 24, weight: .regular)
        $0.textColor = .lightGray
        $0.textAlignment = .center
    }
    
	...
}
  • pagerView에서는 이 셀을 가지고 있는 UICollectionView가 존재
final class PagerView: UIView {
    private lazy var collectionView: UICollectionView = {
        UICollectionView(
            frame: .zero,
            collectionViewLayout: UICollectionViewFlowLayout().then {
                $0.scrollDirection = .horizontal
                $0.minimumLineSpacing = 0
                $0.minimumInteritemSpacing = 0
            }
        ).then {
            $0.isScrollEnabled = true
            $0.showsHorizontalScrollIndicator = false
            $0.isPagingEnabled = true
            $0.backgroundColor = .clear
            $0.clipsToBounds = true
            $0.register(PagerCell.self, forCellWithReuseIdentifier: "pager")
        }
    }()
    
    ...
}
  • 초기화 할때 items값을 받도록하여, 이 값을 셀에 그리는 코드 추가
private let items: [String]

init(items: [String]) {
    self.items = items
    super.init(frame: .zero)
    setup()
}

private func setup() {
    collectionView.delegate = self
    collectionView.dataSource = self
    
    addSubview(collectionView)
    collectionView.snp.makeConstraints {
        $0.edges.equalToSuperview()
    }
}

...

extension PagerView: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        items.count
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "pager", for: indexPath) as? PagerCell
        else { return UICollectionViewCell() }
        cell.prepare(title: items[indexPath.row])
        return cell
    }
}

extension PagerView: UICollectionViewDelegateFlowLayout {
    func collectionView(
        _ collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAt indexPath: IndexPath
    ) -> CGSize {
        frame.size
    }
}

 

스크롤 fitting 구현 방법은 다음 글에서 계속) - 스크롤되는 PagerView 구현 방법 - Tab과 Pager 스크롤 싱크 맞추기

 

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

Comments