iOS) 스크롤에 따라서 동적으로 뷰의 높이조절

1 minute read

scrollViewDidScroll(_:)

레이아웃 잡기

  • tableView.contentInset.top 과 같이 inset 을 주는 방법도 있다.
let table = UITableView(frame: .zero, style: .grouped)
table.contentInset = UIEdgeInsets(top: 200, left: 0, bottom: 0, right: 0)
table.contentOffset.y = -200
  • 나는 다른 방법을 생각해봤고 UITableView header 의 크기를 custom UIView 만큼 설정해줘서 tableview 위에 custom UIView 를 얹었다.
// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return self.view.frame.height*(2/7) - 44
    }
    
}
  • 앞서 언급한 contentInset 을 주게된다면 contentOffset 가 변하게 된다. 그래서 contentOffset.y 를 사용해서 동적으로 높이 조절할 경우 높이 계산하는 알고리즘이 조금 다를 수 있다는 점!

출처 : iOS ) ContentInset

스크롤에 영향을 받는 동적 높이를 설정하기

updateConstraints()

  • 제약 조건을 변경할 때 재정의한 메서드를 사용하게 된다.
  • 변경을 하려면 뷰에서 setNeedsUpdateConstraints() 를 호출합니다. 그리고 시스템은 레이아웃이 발생하기 전에 updateConstraints() 구현을 호출합니다.
  • 구현의 마지막 단계로 [super updateConstraints]를 호출합니다.

출처 : Apple Developer Documentation

그런데. 재정의할때 내 의도는 스크롤뷰의 스크롤오프셋을 통해서 높이 조절을 하고싶었는데 재정의하게되면서 스크롤 오프셋 값을 가져오지…못하지 않는가…

그래서 방향을 틀었다. 제약조건을 변수에 저장해서 바꾸어주기로 했다. 하지만 변수를 저장하면 뭐하겠는가 IBOutlet 처럼 연동이 안되는데…

중첩된… constraint… 무섭다

SnapKit 의 updateConstraints() 사용했다.

해보는김에 조금 어색하지만 글씨크기도 줄여보았다.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let contenOffsetY = scrollView.contentOffset.y
        let customViewHeight = 220

        if contenOffsetY > 0 {
            if (customViewHeight - Int(contenOffsetY)) > 80 {
// 아래와 같이하게되면 constraint 가 중첩되서 가장 작은 조건의 
//                customNavigationBar.heightAnchor.constraint(equalToConstant: CGFloat(customViewHeight) - contenOffsetY).isActive = true
                if (customViewHeight - Int(contenOffsetY)) > 110 {
                    storyTitleButton.titleLabel?.font = UIFont(name: "NanumMyeongjo", size: 20)
                } else {
                    storyTitleButton.titleLabel?.font = UIFont(name: "NanumMyeongjo", size: 19.7)
                }
                customNavigationBar.snp.updateConstraints({ make in
                    make.height.equalTo(CGFloat(customViewHeight) - contenOffsetY)
                })
            } else {
//                customNavigationBar.heightAnchor.constraint(equalToConstant: 100).isActive = true
                customNavigationBar.snp.updateConstraints({ make in
                    make.height.equalTo(80)
                })
                storyTitleButton.titleLabel?.font = UIFont(name: "NanumMyeongjo", size: 19.5)
            }
        }

이러한 방법 말고도 쉬운 코드가 있다.

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let y = -scrollView.contentOffset.y
    let height = min(max(y, 80), 220)

    headerView.snp.updateConstraints { make in
        make.height.equalTo(height)
    }
}

결과

Categories:

Updated: