티스토리 뷰

오랜만에 iOS 글을 적는거 같네요.

 

오늘 올려볼 글은 CollectionView를 이용해서 Header를 만들고 Stretch 동작하도록 할거에요.

뮤직 어플등에서 상단에 View를 Stretch 하는 것이에요.

 

이미지를 보여주는게 더 나을것 같아요. 사진은 이쁜 지수.

Storyboard는 최근 사용하지 않아서 코드로 만들어진 부분들을 넣었습니다.

기본 CollectionView 만들기

ViewController에 다음과 같이 만들어 봅시다.

final class ViewController: UIViewController {
    
    private let headerReusableId = "HeaderReusableView"
    private let cellReusableId = "CollectionViewCell"
    
    private lazy var collectionView: UICollectionView = { [unowned self] in
        let view = UICollectionView(frame: .zero, collectionViewLayout: self.collectionViewFlowLayout)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    private lazy var collectionViewFlowLayout: UICollectionViewFlowLayout = {
        let layout = StretchableUICollectionViewFlowLayout()
        layout.sectionInset = .init(top: 10, left: 0, bottom: 0, right: 0)
        layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.width, height: 300)
        return layout
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupCollectionView()
    }
}

private extension ViewController {
    func setupCollectionView() {
        view.addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
            collectionView.rightAnchor.constraint(equalTo: view.rightAnchor),
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        collectionView.register(CollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerReusableId)
        
        collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: cellReusableId)
        
        collectionView.delegate = self
        collectionView.dataSource = self
    }
}

extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 300
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReusableId, for: indexPath)
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        switch kind {
        case UICollectionView.elementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerReusableId, for: indexPath)
            return headerView
        default:
            #if DEBUG
            assert(false, "Don't use this kind.")
            #else
            return UICollectionReusableView()
            #endif
            
        }
    }
}

collectionView

UICollectionView를 초기화하는 부분

 

collectionViewFlowLayout

UICollectionViewFlowLayout을 초기화하는 부분

이곳에서 StretchableUICollectionViewFlowLayout을 가지고 초기화를 하여 줍니다.

 

나머지 부분들중 delegate, datasource 같은 부분들은 설명하지 않을게요.

StretchableUICollectionViewFlowLayout

이것을 만들지 않고 기본적인 UICollectionViewFlowLayout을 이용하면 우리가 아는 CollectionView처럼 스크롤되는 방향대로 그대로 스크롤 됩니다.

final class StretchableUICollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)
        
        guard let offset = collectionView?.contentOffset, let stLayoutAttributes = layoutAttributes else {
            return layoutAttributes
        }
        
        if offset.y < 0 {
            for attributes in stLayoutAttributes where attributes.representedElementKind == UICollectionView.elementKindSectionHeader {
                let diffValue = abs(offset.y)
                var frame = attributes.frame
                frame.size.height = max(0, headerReferenceSize.height + diffValue)
                frame.origin.y = frame.minY - diffValue
                attributes.frame = frame
            }
        }
        return layoutAttributes
    }
}

이 프로젝트의 핵심이라고 할 수 있을거 같습니다.

CollectionViewCell

그냥 표현해주는 collection view cell입니다.

CollectionReusableView

 Image를 View의 높이에 따라서 늘어날수 있도록 AutoLayout을 정의하여 두고 사용하여 줍니다.


프로젝트의 궁금한점은 글로 남겨주시기 바랍니다.

 

git에 프로젝트 전체 올려 두었습니다.

https://github.com/outofcode-example/iOS-UICollectionReusableViewExample

 

outofcode-example/iOS-UICollectionReusableViewExample

UICollectionReusableViewExample. Contribute to outofcode-example/iOS-UICollectionReusableViewExample development by creating an account on GitHub.

github.com

 

'Mobile > iOS' 카테고리의 다른 글

iOS - Swift. SwiftUI. @Environment  (0) 2023.02.07
iOS - Swift. Property Wrappers  (0) 2023.02.06
swift. RealmSwift 이용하여 봅시다.  (0) 2021.04.03
Swift. Method Swizzle.  (0) 2021.01.03
Swift. @dynamicMemberLookup  (0) 2021.01.03
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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 31
글 보관함