스크롤 뷰를 스토리보드에 오토 레이아웃을 적용하여 구현해보자.


들어가며

UIScrollView는 개인적으로 사용할 때마다 헷갈리는 UIKit 클래스 중 하나입니다. 스크롤 뷰를 상속한 UIKit 클래스들이 꽤 있기 때문에 스크롤 뷰는 꽤나 중요한 친구입니다. 스크롤 뷰를 스토리보드에서 사용하려면 항상 빨간 경고를 만나게 됩니다. 이 스크롤 뷰를 스토리보드에서 오토 레이아웃과 함께 사용하는 방법을 정리해보았습니다.


UIScrollView

UIScrollViewUITableView, UITextView, UICollecctionView을 포함하여 몇가지 UIKit 클래스들의 superclass입니다.

스크롤 뷰는 스크롤되는 뷰들을 담고 있는 Content Layout과 화면에 보여지는 Frame Layout으로 나뉘어 집니다. Content layout에는 스크롤 되는 전체 content를 가지고 있고, Frame layout은 잘려서 보여지기 때문에 스크롤 해야 content layout의 다른 contents를 볼 수 있습니다. 이 두개의 키워드를 알고 보시면 더욱 이해하기 쉽습니다.


개발 환경

  • Xcode 11.6
  • Swift 5.3


Vertical ScrollView in Storyboard

이 포스트에서는 세로로 스크롤 할 수 있는 스크롤 뷰를 구현해보겠습니다. 가로는 세로가 익숙해지면 응용하여 충분히 구현할 수 있습니다.

과정은 크게 다음과 같습니다.

  • 스크롤 뷰 오토레이아웃 잡아주기
  • ContentView 추가하기
  • Content View 사이즈 잡아주기
  • Frame Layout 잡아주기
  • Width/Height 잡아주기


스크롤 뷰 오토레이아웃 잡아주기

뷰컨트롤러의 뷰와 스크롤뷰를 구분하기 위해 뷰컨트롤러의 뷰의 background color를 주황색으로 변경하였습니다. 이 뷰컨트롤러의 이름은 VerticalViewController라고 하겠습니다.



이제 VerticalViewController스크롤 뷰를 추가하여 클릭한 뒤 스토리보드 오른쪽 아래에 있는 Add New Constraints 버튼을 눌러 스크롤 뷰에 auto layout을 줍니다. 아래 스크린샷과 같이 스크롤 뷰의 leading, top, trailing, bottom anchor를 스크롤 뷰의 superView의 leading, top, trailing, bottom anchor와 일치하게 constraint를 주고 constant는 0으로 잡아줍니다.

스크롤 뷰가 스토리보드에서 자동으로 늘어나지 않으면, 직접 스크롤 뷰를 늘려주세요.

위와 같이 constraint를 잡아주면 스크롤 뷰의 Frame Layout GuideContent Layout GuideFrame Layout Guide의 constraint를 설정한 것입니다.



위에서 스크롤 뷰의 leading, top, trailing, bottom에 constraint를 모두 줬는데도 다음과 같이 경고가 뜨게 됩니다. 그 이유는 바로 스크롤 뷰의 content의 사이즈가 정해져 있지 않기 때문에 발생하는 경고입니다.



빨간 화살표 클릭하면 다음과 같은 경고가 뜨게 됩니다.

Has ambiguous scrollable content width/height

스크롤 뷰의 content의 사이즈가 모호하다는 경고입니다.



ContentView 추가하기

이제 스크롤 뷰의 content를 담을 뷰가 필요합니다. 그리고 이 뷰는 실질적인 사이즈가 필요합니다. 그래서 content의 width와 height가 필요합니다. 스크롤 뷰의 frame이 정해져 있어도 실제로 화면에 보여줄 content가 없다면 의미가 없기 때문입니다. 그래서 content를 담을 UIView를 하나 스크롤 뷰에 추가하고 이름을 contentView라고 하겠습니다.



추가된 contentView를 스크롤 뷰의 Content Layout Guide에 오토 레이아웃을 사용해 꽉 채워줍니다.

contentViewcontrol을 누른상태로 Content Layout Guide에 드래그하여 오토 레이아웃을 줄 수 있습니다. 이 방법으로 leading, top, trailing, bottom anchor 모두 constraint를 적용해줍니다.

이와 같은 방식으로 오토 레이아웃을 주면 Leading Space to Content Layout Guide라는 옵션을 볼 수 있는데, contentView의 leading anchor와 Content Layout Guide의 leading anchor를 일치하게 하면서 현재 스토리보드에서 보여지는 두 anchor의 차이만큼 거리(spacing)을 주겠다는 의미입니다. 이렇게 constraint를 적용한 뒤에 나중에 space 값을 바꿔줘도 되고 아니면 스토리보드에 있는 뷰를 원하는 크기로 맞춘 다음에 드래그하여 constraint를 주게되면 constant값을 추가로 수정할 필요가 없습니다.




이렇게 constraint를 잡아줘도 contentView의 실질적인 width와 height가 명확하게 없기 때문에 경고가 뜨게 됩니다.


Content View 사이즈 잡아주기

세로로 스크롤을 하기 위해서는 content view의 가로는 고정되고 세로는 동적으로 변할 수 있어야합니다.

그래서 먼저 contentView의 가로를 스크롤 뷰의 Frame Layout Guide와 동일하도록 지정해야합니다. contentViewcontrol을 클릭한 상태로 드래그하여 Equal widths 옵션을 선택해주고 multiplier를 1로 지정해줍니다. 여기서도 마찬가지로 스토리보드에 보여지는 상태 그대로 Equal widths가 적용되기 때문에 처음에는 1:1 비율이 아니기에 inspector 창에서 바꿔줘야합니다.


contentView 높이는 contentView스크롤 뷰에 꽉 차게 늘린 후, contentView를 control을 누른 상태로 자기 자신에게 드래그하여 높이를 지정해줍니다. 이렇게 되면 contentView의 높이는 현재 스토리보드에 보여지는 contentView의 높이로 고정값이 생기게 됩니다.



하지만 이렇게 고정값을 주게 되면 스크롤에 제한이 생기게 됩니다. 따라서 contentView안에 더 들어올 수 있는 UI 요소들에 고려하여 contentView의 높이가 동적으로 변경될 수 있게 하기 위해 priority를 낮춰줘야합니다.

따라서 contentViewheight constraintpriority를 250으로 낮춰줍니다. 이렇게 되면 contentView의 높이는 완전히 고정된 값이 아니게 되어 동적으로 바뀔 수 있습니다.


사이즈까지 정상적으로 constraint를 줬다면, 오토레이아웃이 정상적으로 적용되고, 스토리보드에 경고가 뜨지 않는 것을 확인할 수 있습니다.



스크롤 뷰의 contentViewUIStackView를 하나 추가하여 동적으로 contentView의 높이가 바뀌는지 확인해보도록 하겠습니다. 스택 뷰를 contentView에 꽉 차도록 오토레이아웃을 준 후에 아래와 같이 코드를 작성해줬습니다. 일정한 랜덤의 크기와 랜덤한 색의 뷰를 생성하여 스택 뷰에 추가해주는 코드입니다.

import UIKit

class VerticalViewController: UIViewController {

    @IBOutlet weak var verticalStackView: UIStackView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureStackView()
    }
    
    private func configureStackView() {
        for _ in 0..<10 {
            let dummyView = randomColoredView()
            verticalStackView.addArrangedSubview(dummyView)
        }
    }
    
    // 랜덤 색상, 100~400 height를 가진 뷰 생성 함수
    private func randomColoredView() -> UIView {
        let view = UIView()
        view.backgroundColor = UIColor(
            displayP3Red: 1.0,
            green: .random(in: 0...1),
            blue: .random(in: 0...1),
            alpha: .random(in: 0...1))
        view.translatesAutoresizingMaskIntoConstraints = false
        view.heightAnchor.constraint(equalToConstant: .random(in: 100...400)).isActive = true
        return view
    }
}


구현 화면

추가된 10개의 View가 모두 스택 뷰로 들어가 정상적으로 스크롤이 되는 것을 확인할 수 있습니다.


마치며

UIScrollView는 처음에는 사용해보기 까다로운 친구입니다. 하지만 content layout과 frame layout 개념을 잘 숙지하면 기본적인 스크롤 뷰를 만드는 것에는 큰 어려움이 없는 것 같습니다. 읽어주셔서 감사합니다. 피드백은 언제나 환영입니다. 😀


References

댓글남기기