업데이트:

Fill Parent


코드를 사용해 Pin Tool에서 마이뷰의 leading, top, trailing, bottom 여백을 모두 0으로 준 것과 동일한 결과가 나오게끔 할 것이다.

세가지 방법으로 적용해보도록 하자.

  • withInitializer() : NSLayoutConstraint 생성자 활용

  • withVisualFormatLang() : Visual Format Language 활용

  • withAnchor() : NSLayout Anchor 활용

먼저 뷰컨트롤러와 소스를 연결한다.

import UIKit

class practiceViewController: UIViewController {

    // 컨테이너뷰 연결
    @IBOutlet weak var container: UIView!
    
    // 마이뷰 연결
    @IBOutlet weak var myView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 뷰를 채우는 3가지 방법
        withInitializer()
        // withVisualFormatLang()
        // withAnchor()
    }
}

extension practiceViewController {
    func withInitializer() {
        // extension을 이용해 함수 정의
    }
}

extension practiceViewController {
    func withVisualFormatLang() {
        
    }
}

extension practiceViewController {
    func withAnchor() {
        
    }
}

1. NSLayoutConstraint 생성자 활용

extension practiceViewController {
    func withInitializer() {
        let leading = NSLayoutConstraint(item: myView, attribute: .leading, relateBy: .equal, toItem: container, attribute: .leading, multiplier: 1.0, constant: 0)
        let top = // 위와 동일, leading을 top으로 바꾼다.
        let trailing = // 위와 동일, leading을 trailing으로 바꾼다.
        let bottom = // 위와 동일, leading을 bottom으로 바꾼다.

        // activate 메소드를 통해 제약 활성화
        NSLayoutConstraint.activate([leading, top, trailing, bottom])
    }
}

스토리 보드의 사이즈 인스펙터창에서 값을 설정했던 것들이 그대로 코드에 있는 걸 볼 수 있다.

생성자로 값을 지정해주었다면 제약을 활성화 시켜주어야 한다.

이전에는 addConstraint 메소드를 통해 제약을 직접 추가해주었다.

이 방법은 잘못된 위치에 제약을 추가하는 경우가 많아 요즘은 올바른 위치에 제약을 자동으로 추가해주는 activate 메소드를 사용한다고 한다.

Autoresizing Mask

만약 이대로 앱을 실행한다면 제약이 제대로 적용되어있지 않을 것이다.

NSAutoresizingMaskLayoutConstraint : 따로 설정을 해주지 않은 경우 오토리사이징 마스크 기반으로 제약이 자동으로 추가된다. 이럴 경우 위에서 추가한 제약과 충돌이 일어나므로 꼭 오토리사이징 마스크 제약이 추가되지 않도록 해주어야 한다.

myView.translatesAutoresizingMaskIntoConstraints = false

위의 한 줄을 withInitializer() 메소드 안에 추가해주면 앱 실행시 제약이 제대로 적용된 걸 확인할 수 있다.

코드로 제약을 추가할 땐 꼭 위의 옵션을 false로 설정해주도록 하자.

2. Visual Format Language 활용

이 방법의 경우 수평과 수직 방향의 제약을 동시에 표현할 수 없다.

그렇기 때문에 개별적으로 두 방향의 제약을 생성해야된다.

extension practiceViewController {
    func withVisualFormatLang() {
        myView.translatesAutoresizingMaskIntoConstraints = false

        let hor = "|[b]|" // b라는 뷰를 상위뷰 기준 여백 없이 배치하라는 의미
        let ver = "V:|[b]|"

        let views: [String: Any] = ["b": myView] // 딕셔너리
        // b에 마이뷰를 지정해주어야 한다.

        let horConstraints = NSLayoutConstraint.constraints(withVisualFormat: hor, options: [], metrics: nil, views: views)
        let verConstraints = // 위와 동일, hor을 ver로 바꾼다.
        // constraints 메소드는 포맷 문자열에 따라 여러개의 제약이 생성될 수 있다.
        // 그러므로 배열을 리턴한다.

        NSLayoutConstraint.activate(horConstraints + verConstraints)
    }
}

수평 제약 문자열 hor의 |[b]|를 자세히 살펴보자.

| [ b ] |
superview의 leading b뷰의 leading 뷰의 이름 b뷰의 trailing superview의 trailing

수직 제약 문자열 ver의 V:은 수직 제약이라는 것을 나타낸다.

주의 문자열에서 사용한 뷰의 이름은 반드시 딕셔너리의 키로 존재해야 한다. 다를 경우 크래시가 난다.

이 방법의 장점은 제약을 직관적으로 확인이 가능하고 작성해야 하는 코드의 길이가 생성자를 활용한 코드보다 비교적 적다는 점이다.

3. NSLayout Anchor 활용

extension practiceViewController {
    func withAnchor() {
        myView.translatesAutoresizingMaskIntoConstraints = false

        myView.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
        // 두 앵커 기준 relation: equal, constant: 0인 제약 추가
        // 상수에 따로 저장하지 않고 isActive 속성을 true로 설정해 활성화 시킬 수 있다.

        myView.topAnchor.constraint(... // 위와 동일, leadingAnchor를 topAnchor로 바꾼다.
        myView.trailingAnchor.constraint(... // 위와 동일, leadingAnchor를 trailingAnchor로 바꾼다.
        myView.bottomAnchor.constraint(... // 위와 동일, leadingAnchor를 bottomAnchor로 바꾼다.
    }
}

Notice: 이 게시물은 KxCoding님의 유튜브를 참고하였습니다.

댓글남기기