Code로 AutoLayout을 줘보자!

이원희·2021년 2월 8일
3

📱 iOS

목록 보기
14/24
post-thumbnail

오늘은 코드로 오토레이아웃을 구현하는 방법을 알아보자!

Storyboard에 화면 그리는걸 사실 별로 안 좋아해서 Xib로 빼거나 코드로 화면을 그렸었다.
나는 Anchor를 이용해서 화면을 그렸는데 프로젝트를 하면서 팀원이 Anchor가 아닌 방식으로 구현해와서 다른 방법이 더 있는지 이번 기회에 알아봤다.

이 화면을 코드로 짜보도록 하자!

Button.centerX = View.centerX
Button.centerY = View.centerY
Label.top = Button.bottom
Label.centerX = Button.centerX


NSLayoutConstraint

공식문서를 먼저 봐보자.

NSLayoutConstraint는 제약 기반의 레이아웃 시스템에서 충족해야하는 두 인터페이스 개체 간의 관계라고 나온다.

NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0.0)

NSLayoutConstraint는 위처럼 정의할 수 있다.

item: 제약을 지정할 UI
attribute: 제약을 지정할 UI의 제약 속성
relatedBy: 제약을 지정할 UI와 제약의 기준이 되는 UI 사이의 관계
toItem: 제약의 기준이 되는 UI
attribute: 제약의 기준이 되는 UI의 제약 속성
multiplier: 제약의 비율
constraint: 제약의 상수값

화면 만들기

let button = UIButton()
        button.setTitle("Test Button", for: .normal)
        button.backgroundColor = .blue
        self.view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            NSLayoutConstraint(item: button, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0.0),
            NSLayoutConstraint(item: button, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1.0, constant: 0.0)
        ])
        
        let label = UILabel()
        label.text = "Test Label"
        label.textColor = .black
        self.view.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: button, attribute: .centerX, multiplier: 1.0 , constant: 0.0),
            NSLayoutConstraint(item: label, attribute: .top, relatedBy: .equal, toItem: button, attribute: .bottom, multiplier: 1.0, constant: 0.0)
        ])


NSLayoutAnchor

공식문서를 먼저 봐보자.

NSLayoutAnchor는 쉬운 API 사용으로 레이아웃 제약 객체를 생성하기 위한 클래스이다.
오호... 쉽다는데 얼마나 쉽다는 걸까?
공식문서에 나와 있는 예제를 한 번 봐보자.

// Creating constraints using NSLayoutConstraint
NSLayoutConstraint(item: subview,
                   attribute: .leading,
                   relatedBy: .equal,
                   toItem: view,
                   attribute: .leadingMargin,
                   multiplier: 1.0,
                   constant: 0.0).isActive = true

NSLayoutConstraint(item: subview,
                   attribute: .trailing,
                   relatedBy: .equal,
                   toItem: view,
                   attribute: .trailingMargin,
                   multiplier: 1.0,
                   constant: 0.0).isActive = true


// Creating the same constraints using Layout Anchors
let margins = view.layoutMarginsGuide

subview.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
subview.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true

NSLayoutConstraint를 사용한 코드(위)와 NSLayoutAnchor를 사용한 코드(아래)가 있다.
두 코드 다 같은 제약 조건인데 NSLayoutAnchor가 더 쉬어보인다.
공식문서에서는 NSLayoutAnchor 클래스를 사용하면 NSLayoutConstraint API를 직접쩍으로 쓰는 것보다 몇 가지 이점이 있다고한다.

  • 코드가 더 clean해지고, 더 간결해지고, 더 읽기 쉬어진다.
  • NSLayoutConstraint.Attribute 서브 클래스는 추가적으로 Type 검사를 제공하여 유효하지 않은 제약 조건을 생성하는 것을 방지한다.

(NSLayoutConstraint.Attribute는 left, right, leading, trailing 등이 속한다. 공식문서)

화면 만들기

let button = UIButton()
        button.setTitle("Test Button", for: .normal)
        button.backgroundColor = .blue
        self.view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        
        let label = UILabel()
        label.text = "Test Label"
        label.textColor = .black
        self.view.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        
        label.topAnchor.constraint(equalTo: button.bottomAnchor).isActive = true
        label.centerXAnchor.constraint(equalTo: button.centerXAnchor).isActive = true


Visual Format

공식문서를 먼저 봐보자.

Visual Format은 ASCII 아트와 유사한 시각적 형식 문자열로 설명된 제약 조건을 만드는 방식이다.

class func constraints(withVisualFormat format: String, 
               options opts: NSLayoutConstraint.FormatOptions = [], 
               metrics: [String : Any]?, 
                 views: [String : Any]) -> [NSLayoutConstraint]

위와 같은 코드를 사용한다.

format: 제약 조건에 대한 형식 사양
options: 시각적 형식 문자열의 모든 개체에 대한 속성 및 레이아웃 방향을 설명하는 옵션
matrics: 시각적 형식 문자열에 나타나는 상수 dictionary이다.
views: 시각적 형식 문자열에 표시되는 보기 dictionary이다. key는 시각적 형식 문자열에 사용된 문자열 값, value는 view 개체여야 한다.

여기서 Visual Format Language를 확인할 수 있다.

예시

let button = UIButton()
        button.setTitle("Test Button", for: .normal)
        button.backgroundColor = .blue
        
        self.view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
                
        
        let views = [
            "button" : button
        ]
        
        let format = "H:|[button]|"
        let format2 = "V:|[button]|"
        
        var constraints = NSLayoutConstraint.constraints(withVisualFormat: format, options: [], metrics: nil, views: views)
        constraints += NSLayoutConstraint.constraints(withVisualFormat: format2, options: [], metrics: nil, views: views)
        NSLayoutConstraint.activate(constraints)


마무리

오늘은 스토리보드를 사용하지 않고 코드로 오토레이아웃을 설정하는 방법을 알아봤다.
나는 항상 Anchor를 사용했었는데 다양한 방법이 있는지 이번에 알았다.
내가 생각할때는 Anchor가 가장 보기 쉽고, 간단해 보인다.
그럼 이만👋

1개의 댓글

comment-user-thumbnail
2021년 5월 7일

라자냐 글 잘봤습니다!! 정리를 너무 잘해놓으셨네요 ㅎㅎ

답글 달기