ScrollView 직접 사용해보기

고라니·2023년 8월 28일
0

TIL

목록 보기
27/67

이전에 UIScrollView에 대한 개념과 여러 프로터이와 메서드에 대해 알아보았다.
이번에는 직접 스크롤뷰를 사용해보겠다.

Frame Layout과 Cotent Layout

iOS 11부터 추가된 기능으로 이 두 가이드는 UIScrollView의 레이아웃을 더 명확하고 직관적으로 설정하기 위한 도구이다. 직접 구현해보기 전에 이 두 개념을 알아보겠다.

  1. frmaLayoutGuide: UIScrollView의 frame에 관련된 제약 조건을 설정하는 데 사용된다. 즉 스크롤 뷰로 보고 있는 실제 크기를 정의한다.

  2. contentLayoutGuide: 스크롤 뷰의 내부 contetn 크기와 관련된 제약 조건을 설정하는데 사용된다. 기존에는 contentSize 속성을 사용하여 스크롤 가능한 영역의 크기를 직접 설정했지만, contentLayoutGuide를 사용하여 오토 레이아웃 제약 조건을 활용하여 스크롤 가능한 영역 크기를 동적으로 설정 가능하다.

구조

컨텐츠 사이즈가 프레임 사이즈보다 큰 경우 스크롤이 가능하다. 만약 컨텐츠 사이즈가 더 작다면 스크롤의 의미가 없다.

세로스크롤

fram layout 너비와 content layout 너비가 동일하면 세로 스크롤만 가능하다.

가로스크롤

반대로 높이가 동일하면 가로스크롤이 가능하다.

스토리보드로 스크롤뷰 구현하기

스토리보드에서 Frame Layout과 Contet Layout를 활용해서 ScrollView를 구현해보기.
가로스크롤이 불가한 세로 스크롤을 구현.

스크롤뷰 추가하기

헷갈리지 않게 배경색상을 미리 적용하였다.

스크롤뷰를 추가하고 드래그하여 어느정도 크기를 잡아준다. (크기를 미리 잡아주지 않은 상태에서 제약조건 등을 설정하면 원하는대로 설정이 안되는 경우가 있었음.)

안전영역을 제외한 전체 크기의 스크롤뷰로 구현하기 위해 제약조건을 모두 0으로 설정한다.

자동으로 Content Layout Guide와 Frame Layout Guide가 생성된 것을 볼 수 있다.

문제 없이 잘 따라 해도 경고문구가 뜨는것을 알 수 있다. 내용을 확인해보면 스크롤 가능한 컨텐츠 사이즈가 모호하다고 한다. 당연히 아직 컨텐츠관련 설정을 해주지 않았기 때문이다.

Content View 추가하기

View를 ScrollView에 추가해준다. 그리고 ScrollView와 마찬가지로 크기를 미리 잡아주는것이 좋다.

Content Layout 설정

새로 추가한 View의 제약조건을 Content Layout Guide로 설정한다. 이 때 제약 조건 수치를 잘 확인해서 의도한대로 설정 되었는지 확인하는것을 권장한다. (이부분 때문에 시간이 좀 지체되었음...)

Frame Layout 설정

세로 스크롤만 가능하게 하기 위해 View의 너비를 ScrollView의 프레임 사이즈와 동일하게 설정한다. 그리고 컨텐츠의 높이를 설정한다. (위에서 설명했던 내용대로 프레임 사이즈보다 컨텐츠 사이즈가 커야만 스크롤에 의미가 있음)

여기까지 진행했다면 좀전까지 떠있던 오류는 없어진다.

Contents 추가하기

생성한 뷰 내부에 라벨을 넣어 보겠다.
기존 스토리보드에서 라벨을 추가하는 것과 동일한 방법으로 추가하면 된다. 다른점은 스크롤하여 기존화면에 보이지 않던 위치까지 배치 가능하다는 것이다.

라벨을 A~B 라벨을 추가하고, 가운데 정렬, A~C: top 제약조건은 300, D: bottom 제약조건 0

확인하기

계획한대로 기본 상태에서 A와 B가 상단 300간격으로 배치되어 있는 것을 볼 수 있고, 스크롤을 내리면 C가 보이고 다음으로 D가 하단에 딱 붙어 있는것을 볼 수 있다.

코드로 스크롤뷰 구현하기

코드를 통해Frame Layout과 Contet Layout를 활용해서 ScrollView를 구현해보기.

UI 구성요소 초기화하기

let scrollView: UIScrollView = UIScrollView()
let contentView: UIView = UIView()
let labelA: UILabel = UILabel()
let labelB: UILabel = UILabel()
let labelC: UILabel = UILabel()
let labelD: UILabel = UILabel()

뷰 설정

func setupViews() {

    scrollView.translatesAutoresizingMaskIntoConstraints = false
    contentView.translatesAutoresizingMaskIntoConstraints = false
    labelA.translatesAutoresizingMaskIntoConstraints = false
    labelB.translatesAutoresizingMaskIntoConstraints = false
    labelC.translatesAutoresizingMaskIntoConstraints = false
    labelD.translatesAutoresizingMaskIntoConstraints = false

    labelA.text = "A"
    labelB.text = "B"
    labelC.text = "C"
    labelD.text = "D"

    view.addSubview(scrollView)

    scrollView.addSubview(contentView)

    contentView.addSubview(labelA)
    contentView.addSubview(labelB)
    contentView.addSubview(labelC)
    contentView.addSubview(labelD)
}

제약사항 설정

func setupConstraints() {
        NSLayoutConstraint.activate([

            // scrollView contstaints
            scrollView.topAnchor.constraint(equalTo: view.topAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),

            // contentView constraints
            contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
            contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
            contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor),
            contentView.heightAnchor.constraint(equalToConstant: 2000),

            // labelA constraints
            labelA.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 300),
            labelA.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),

            // labelB constraints
            labelB.topAnchor.constraint(equalTo: labelA.topAnchor, constant: 300),
            labelB.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),

            // labelC constraints
            labelC.topAnchor.constraint(equalTo: labelB.topAnchor, constant: 300),
            labelC.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),

            // labelD constraints
            labelD.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -200),
            labelD.centerXAnchor.constraint(equalTo: contentView.centerXAnchor)
        ])
    }

ViewDidLoad에서 호출

override func viewDidLoad() {
        super.viewDidLoad()

        setupViews()
        setupConstraints()
    }

스토리보드로 구현한것과 동일하게 구현하였다. 일정 수치는 약간 차이가 있게 구현하였음(높이: 2000, D의 bottom제약: 200)

스토리보드를 통해 설정한 대로, 그대로 코드로 설정해주면 된다. 만약 제약조건을 코드로 설정하는방법을 모른다면 NSLayoutConstraint과련 정보를 보고 오는것이 좋다.

마치면서

여러 프로퍼티와 메서드를 사용하지 않고 아주 간단한 형태로 구현해보면서 Frame Layout과 Content Layout을 배워보았다. 이 두 개념이 업데이트 되기 이전의 방식대로 구현하는것도 가능하지만, Frame Layout과 Content Layout을 활용하면 동적으로 사이즈 조절이가능하고, 유연하고, 손쉽게 스크롤뷰를 구현할 수 있다. 스크롤뷰는 대부분의 앱에서 많이 사용되기 때문에 자주 사용하면서 다양한 기능들에 대해서도 알아봐야 겠다.

profile
🍎 무럭무럭

0개의 댓글