본문 바로가기

MOBILE/ios

[iOS] SnapKit을 사용하여 AutoLayout constraint 설정하기

AutoLayout을 사용하여 쉽게 view 객체들 간의 constraint를 설정하는 라이브러리를 알아보자

실제로 인턴 다니는 회사에서 사용하는 라이브러리인데, 처음 접해보고 진짜 너무 편하고 좋아서 사이드 프로젝트에도 적용하고 있음..

 

1. SnapKit 공식 문서

snapkit은 cocoapod을 통해 설치 가능하다.

 

GitHub - SnapKit/SnapKit: A Swift Autolayout DSL for iOS & OS X

A Swift Autolayout DSL for iOS & OS X. Contribute to SnapKit/SnapKit development by creating an account on GitHub.

github.com

깃허브를 방문하면 자세한 정보들을 얻을 수 있고 기본 사용법을 설명하는 공식 사이트도 있다

 

Requirements

Requirements iOS 8.0+ / Mac OS X 10.11+ / tvOS 9.0+ Xcode 9.0+ Swift 4.0+ Communication If you need help, use Stack Overflow. (Tag ‘snapkit’) If you’d like to ask a general question, use Stack Overflow. If you found a bug, open an issue. If you have

snapkit.github.io

 

 

2. AutoLayout

그럼 auto layout이 도대체 무엇이길래 굳이 snapkit을 사용하여 view를 설정해야 할까?

apple developer 에서 제공하는 auto layout 문서를 읽어보자 (물론 좀 오래되긴 했지만서도...)

https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html

 

Auto Layout Guide: Understanding Auto Layout

 

developer.apple.com

 

auto layout은 view에 걸린 constraint를 바탕으로 view 계층에서 view들의 위치와 크기를 동적으로 계산하는 것이다.

이러한 제약사항 바탕의 접근은 UI를 내부적, 외부적 요인 모두에 반응할 수 있도록 구성 가능하다.

외부적 요인

외부적 요인은 상위 뷰의 보양과 크기가 변할 때 발생한다. 각각의 변화마다 개발자는 반드시 view 계층의 레이아웃을 가능한 최선의 공간만 사용할 수 있도록 업데이트 해야한다. 다음은 외부적 요인의 예시이다.

 

  • 사용자가 window의 크기를 조절하는 경우 (OS X).
  • 사용자가 iPad의 splitl view를 들어가거나 나오는 경우 (iOS).
  • 디바이스가 회전하는 경우 (가로에서 세로 혹은 그 반대) (iOS).
  • 전화 또는 녹음이 나타나거나 사라지는 경우 (iOS).
  • 다른 사이즈의 클래스를 지원 하는 경우
  • 다른 화면 크기를 지원하는 경우

이러한 변화의 대부분은 런타임에 발생한다. 또한 이들은 앱에서 동적인 반응을 요구한다. 동적으로 화면 크기가 변화하지 않더라도, 적응형 인터페이스는 앱이 iPhone 4s, iPhone 6 plus 또는 iPad에서도 동일하게 잘 동작하도록 한다. auto layout은 iPad에서 split view와 slide over를 지원하는 중요한 요소이다.

 

내부적 요인

내부적 변화는 UI의 뷰와 컨트롤의 크기가 변화할 때 발생한다. 다음은 외부적 요인의 예시이다.

 

  • 앱이 변화함으로써 컨텐츠가 화면에 표시되는 경우
  • 앱이 국제화를 지원하는 경우(internalization)
  • app이 Dynamic Type을 지원하는 경우 (iOS).

앱의 컨텐츠가 변화하는 경우, 새로운 컨텐츠는 이전보다 새로운 layout을 요구한다. 이러한 상황은 text 또는 이미지를 화면에 보여주는 경우에 주로 발생한다. 

 

이렇게 화면의 크기는 앱 실행 중에 동적으로 변하는 경우가 많기 때문에

아무데나 배치했다가는 화면 크기가 변화면 view 객체 또한 아무데나 위치하게 된다.

따라서 view 객체에게 화면 크기에 따른 제약사항을 걸어서 일정한 위치를 가질 수 있도록 보장해야 한다.

 

3. NSLayoutConstraint

이를 위한 ios에서의 객체가 있다. 바로 NSLayoutConstraint이다.

 

Apple Developer Documentation

 

developer.apple.com

하지만 생각보다 이 클래스는 비효율적이다.

따라서 이를 바탕으로 한 SnapKit과 같은 라이브러리를 사용하는 것이 더 효율적이다.

 

4. AutoLayout 제약사항

auto layout의 제약사항은 다음과 같다

이를 바탕으로 위쪽에 제약을 걸고 싶다면 Top을, 왼쪽에 제약을 걸고 싶다면 Left 또는 Leading을 설정해주는 방식으로 제약사항을 설정 해야 한다.

 

 

5. SnapKit 기본 사용법

다음과 같이 box 객체의 모든 면에 제약사항을 주는 경우를 생각하자

 

 

snapkit의 메소드들은 다음과 같다.

 

 

makeConstraint: 일반적으로 Constraint layout을 설정할 때

box.snp.makeConstraints { make in
    make.top.equalTo(superview).offset(20)
    make.left.equalTo(superview).offset(20)
    make.bottom.equalTo(superview).offset(-20)
    make.right.equalTo(superview).offset(-20)
}

box.snp.makeConstraints { make in
    make.edges.equalTo(superview).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}

 

equalTo() 메소드를 사용하여 숫자, 또는 다른 view객체에 일치하도록 제약사항을 걸 수 있으며, offset() 메소드로 offset을 줄 수 있다.  superview에 일치하게 만들 경우에는 equalToSuperview() 를 사용해도 된다.

 

remakeConstraints: 이미 설정되어있는 Constraint layout을 유지하고, 추가 사항만 업데이트하기

box.snp.updateConstraints{ make in
    make.top.equalTo(superview).offset(20)
    make.left.equalTo(superview).offset(20)
    make.bottom.equalTo(superview).offset(-20)
    make.right.equalTo(superview).offset(-20)
}

 

updateConstraints: 이미 설정되어있는 Constraint layout을 모두 제거하고, 제약사항을 다시 설정하기

box.snp.remakeConstraints{ make in
    make.edges.equalTo(superview).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}

 

 

removeConstraints: 설정되어있는 모든 Constraint layout을 제거하기 

box.snp.removeConstraints()

6. Attribute

edges

make.top.left.bottom.right 을 한번에 적용하기 (반시계 방향으로 적용됨)

make.edges.equalTo(view2);
make.edges.equalTo(superview).inset(UIEdgeInsets(top: 5,left: 10, bottom: 15, right: 20))

size

make.width.height 를 한번에 적용하기

make.size.equalTo(superview).offset(100)

center

중심 좌표에 constraint 적용하기

make.center.equalTo(superview).offset(5) // superview (0,0) 이라면 view (5, 5)

chain 문법 지원

같은 값을 가질 때 속성들 한번에 적용하기

make.left.right.bottom.equalTo(superview)

 

iOS 11 이상 Safe Area 적용하기

ios 11부터 safe area가 생기면서 layout 제약사항에서 고려해야 하는 부분이 추가로 발생하였다

이때는 safeAreaLayoutGuide 속성 사용하여 설정 가능하다.

 

box.snp.makeConstraints { make in
    make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top)
}

 

7. 이를 제외하고 SnapKit 헷갈리는 것 정리

(1) label을 제외하고 모든 객체는 4개 속성이 모두 constraint 잡혀 있어야 함

 

(2) Edges 속성 적용하면 모든 곳에 한번에 적용 가능

 

(3)Inset 대신에 offset 사용하기

 

(4) Intrinsic content size 구분하고 constraint 맞추기

 

 
Intrinsic Contet Size Width
Intrinsic Contet Size Height
UIView
X
X
UISlider
O
X
UILabel, UIButton, UISwitch, UITextField
O
O
TextView, ImageView
Content에 따라 변화함