[iOS] Stretchable Headers

Youn·2023년 1월 27일
0

iOS

목록 보기
4/4
post-thumbnail

참고

1. Table View

1. Table Header View 생성

// SHTableHeaderView.swift
final class SHTableHeaderView: UIView {
      /**
		init () 
        setSubViews ()
        setSubViewLayouts() -
      */
      
    func scrollViewDidScroll(scrollView: UIScrollView) {
        let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
        imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
    }
}

setSubViewLayouts

  1. 이미지 뷰 단독
    • 이미지의 넓이, centerX, bottom 을 superView(headerView) 와 동일하게 설정
    • 이미지의 높이도 superview 와 동일하게 설정, 별도 변수로 저장
  2. 컨테이너 뷰 사용
    • 이미지뷰의 bottom constraint 를 통해 아래로 스크롤 시 작아지는 효과를 더할 수 있음
    • 컨테이너 뷰의 넓이, centerX, 높이를 superView 와 동일하게 설정
    • 이미지뷰의 넓이, 높이, bottom 을 컨테이너 뷰와 동일하게 설정
        func scrollViewDidScroll(scrollView: UIScrollView) {
            let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
    	    containerView.clipsToBounds = offsetY <= 0
        	imageViewBottom.constant = offsetY >= 0 ? 0 : -offsetY / 2 // 추가
        	imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
    	}

2. Table Header View 설정

// ViewController.swift
    private lazy var tableViewHeaderView = SHTableHeaderView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 200))
    
    @IBOutlet private weak var tableView: UITableView! {
        didSet {
            tableView.tableHeaderView = tableViewHeaderView
        }
    }

3. scrollViewDidScroll 호출

// ViewController.swift
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let headerView = self.tableView.tableHeaderView as! SHTableHeaderView
        headerView.scrollViewDidScroll(scrollView: scrollView)
    }

결과

좌 - 이미지뷰를 컨테이너로 한번 더 감쌌을 때
우 - 이미지뷰 단독 설정


Source - (private)

2. Collection View

1. 별개의 View

  • 컬렉션 뷰와 별개로 헤더용 뷰 생성, scrollViewDidScroll 에서 레이아웃 조절

2. FlowLayout

class CollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)
        
        layoutAttributes?.forEach { attribute in
            if attribute.representedElementKind == UICollectionView.elementKindSectionHeader {
                guard let collectionView = collectionView else { return }
                let contentOffsetY = collectionView.contentOffset.y
                
                if contentOffsetY < 0 {
                    let width = collectionView.frame.width
                    let height = attribute.frame.height - contentOffsetY
                    attribute.frame = CGRect(x: 0, y: contentOffsetY, width: width, height: height)
                }
            }
        }
        
        return layoutAttributes
    }
    
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return true
    }
    
    // ...

}`

3. Compositional Layout

// MARK: - HeaderView 
final class StretchyCollectionHeaderView: UICollectionReusableView {
    // ...
    // MARK: - Init
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    /// Create Subviews
    private func createViews() {
    }
    
    /// Setup View Constraints
    func setViewConstraints() {
    }
    
    /// Notify View of scroll change from container
    public func scrollviewDidScroll(scrollView: UIScrollView) {
        containerViewHeight.constant = scrollView.contentInset.top
        let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
        containerView.clipsToBounds = offsetY <= 0
        imageViewBottom.constant = offsetY >= 0 ? 0 : -offsetY / 2
        imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
    }
    
}

// MARK: - ViewController
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let header = homePageCollectionView.supplementaryView(forElementKind: HomePageViewController.sectionHeaderElementKind, at: IndexPath(item: 0, section: 0)) as? StretchyCollectionHeaderView {
                header.scrollviewDidScroll(scrollView: homePageCollectionView)
     }
}
profile
youn

0개의 댓글