모바일 프로그래밍/iOS기초

[iOS - Swift기초] 오토 레이아웃(Auto Layout) 기초(정리중)

Dannian 2021. 1. 13. 15:38
반응형

이번 포스트는 오토 레이아웃(Auto Layout)관련 정리입니다.

가끔 채용공고를 보면 다음과 같은 내용이 자격 요건에 들어있는 경우가 있습니다.

- Auto Layout(storyboard) 에 대한 이해도를 가지신 분

Swift 또는 Objective-C이해도, 몇년차 이상, 컴퓨터 공학 전공 이런 내용은 코딩이나 문제 해결 능력 때문일 테고, 저건 대체 뭔데 요구를 하는 걸까요?

잠깐이나마 Xcode Project를 만들고 건들여보셨다면 스토리보드(Storyboard)는 앱의 User Interface(UI, 사용자 인터페이스)를 보기 편하도록 시각적으로 표현해주는 것이라는 걸 아실 겁니다.

그럼 오토 레이아웃은 뭘까요?

 

1. 정의

먼저 Apple의 가이드를 한 번 보겠습니다.

 

Auto Layout Guide: Understanding Auto Layout

 

developer.apple.com

Auto Layout dynamically calculates the size and position of all the views in your view hierarchy, based on constraints placed on those views. For example, you can constrain a button so that it is horizontally centered with an Image view and so that the button’s top edge always remains 8 points below the image’s bottom. If the image view’s size or position changes, the button’s position automatically adjusts to match.
This constraint-based approach to design allows you to build user interfaces that dynamically respond to both internal and external changes.

위의 페이지의 가장 처음에 정의되어있는 내용입니다.

오토 레이아웃이라 함은 뷰에 설정되어있는 제약조건(Constraints)을 기반으로 해서 동적으로 크기와 위치를 계산하는 것이라고 하네요.

즉, 디바이스의 View 사이즈에 따라 제약조건에 맞게 위치와 사이즈가 동적으로 조절되어 어느 디바이스에서건 원하는 식으로 표현되도록 하는 것을 의미합니다.

 

2. 예시

그냥 글로 보면 아 그렇구나 싶은데, 정확히 어떤 상황에 사용되는 건지는 헷갈릴 수 있습니다. 따라서 직접 구현해보면서 알아보도록 하겠습니다.

먼저 간단한 예제 프로젝트를 만들어봅시다.

예제 프로젝트를 하나 만듭니다.

Xcode를 실행해서 새로운 Project를 생성하고, 기본 템플릿을 App으로 해서 만듭니다.

Product name, team, organization identifier를 설정하고 Next를 눌러서 프로젝트를 저장합니다.

기본 템플릿을 설정하면 Project의 옵션을 선택하는 창이 나옵니다.

해당 창에서 Product Name, Team, Organization Identifier 등을 설정하고 Next를 누릅니다.

이때 Interface를 설정하는 부분을 Storyboard로 합시다.(이 예제에서는 SwiftUI를 사용하지 않으니까요)

 

2-1. 상위 뷰 기준 Auto Layout 사용하기

생성된 프로젝트의 Main.storyboard의 ViewController Scene에 Label을 하나 추가합니다.

그 후 생성된 프로젝트의 Main.storyboard를 선택하고, ViewController Scene에 Label을 하나 추가합니다.

일단 제약조건 없이 한 번 시뮬레이터에서 Run해봅시다.

Label의 text를 원하는 대로 작성하고, 시뮬레이터를 설정한 후 Run을 합니다.

iPhone 8 에서 실행 결과

별다른 제약 조건 없이 Storyboard에서 가운데에 Label을 넣고 Text를 입력했는데, iPhone 8에서 실행 결과는 Label의 위치가 가운데가 아닌 것을 볼 수 있습니다.

디바이스에 따라서 사이즈는 변경이 되었는데, 정작 lbText는 포지션이 일정하기 때문에 위치가 다른 문제가 발생하는 것이죠. 이런 문제를 한 번 해결해 보도록 하겠습니다.

Alignment Constraints의 Horizontally in container 항목을 체크해줍니다.

먼저 Label을 선택하고, Storyboard 편집하단 하단에서 Add New Alignment Constraints를 선택 후, Horizontally in container를 선택합니다.(Y축 가운데 정렬은 아직 하지 않기 때문에 Vertically in Container항목은 체크하지 않습니다!)

Missing Constraints라고 경고가 나옵니다!

Horizontally in Container항목만 추가하면 위의 이미지 처럼 붉은 경고 마크가 나오고, 해당 마크를 클릭하면 Missing Contstraints라는 경고가 나옵니다. 여기서는 Y Position이 없다는 이유가 나옵니다.

Y Position이 문제라면, 지금은 X Position은 해결되었다는 의미겠죠.

우리가 체크를 한 Horizontally in Container항목은 Parent View의 Center X값을 기준으로 선택한 view의 Center X값을 정의하는 것입니다. 아까 체크 할 때 value를 0으로 했기 때문에 지금은 Parent View의 Center X와 label의 Center X가 일치하는 상태일 것입니다.

그럼 Y position 해결은 어떻게 해야할까요?

Add New Alignment Constraints의 Vertically in Container를 선택해서 상위뷰의 Center Y 값 기준으로 맞추는 것도 방법이겠고, 특정 위치를 기준으로 잡는 것도 가능합니다. 우리는 일단 상위뷰의 Top 기준으로 위치를 잡아보도록 하겠습니다.

아까 선택한 Add New Alignment Constraints 버튼의 우측에 위치한 Add New Contstraints를 선택해서 Spacing to nearest neighbor의 Top 부분을 선택한 후 가장 하단의 Add를 선택합니다. 그러면 Storyboard가 다음과 같이 표시가 됩니다.

Center X, Top constraints가 선언된 Label의 상태

문제가 되던 Missing Constraints도 해결 되었습니다. 이제 다시 Run을 해봅시다.

가운데 정렬, Parent View 기준 Top 간격 80을 준 상태

X좌표는 가운데 정렬, Y좌표는 상위 뷰의 Top과 Label의 Top간에 80의 간격이 있는 상태로 표시가 됩니다. 

 

2-2. 다른 View 기준 Auto Layout 사용하기

새로운 UIView를 추가합니다!

이전에 생성하고 위치를 잡은 Label을 기준으로 새로운 UIView의 위치를 정해보겠습니다.

먼저 UIView를 추가하고, 백그라운드 컬러를 원하는 색상으로 바꿔서 놓습니다. 이 상태로 Run을 해 보면

위치가 다르게 표시되는 UIView

처음에 Label을 넣었을 때 처럼 위치가 원하는 곳에 나오지 않습니다. 이제 이 것을 원하는 위치에 두겠습니다.

저는 Label 의 Bottom을 기준으로 20만큼 아래, 상위 View Trailing기준 10 만큼 떨어진 곳에 UIView를 두려고 합니다.

제약조건은 원하는 View를 클릭 후 Control + Drag로도 설정 할 수 있습니다.

Label에 대해서 Vertical Spacing, 상위 View에 대해서 Align Trailing을 설정합니다.

딱 이만큼 하면 또다시 Missing Constraints가 나오며, Need Constraints for: height, Need constraints for: X position or Width라고 나옵니다.

제약조건이 더 필요하다고 합니다.

각각의 부족한 제약조건에 대한 이유를 살펴보면, 우리는 먼저 Vertical Spacing에대해서 정의를 했습니다.

Label의 Bottom과 새로 추가한 View의 Top간에 20의 Spacing을 준다는 것이 해당 제약조건입니다.

하지만, 새로 추가한 View의 Height는 정의되지 않았습니다. 그래서 Xcode에서는 해당 제약조건이 필요하다는 경고를 보인 것입니다.

이 경우 2가지의 방법이 있습니다.

  • 다른 View와의 간격을 설정해서 동적인 Height 변경이 이루어지도록 설정하는 것
  • 고정된 특정 값을 Height로 설정하는 것.

첫 번째 동적인 Height 설정은, 가장 처음 Label을 설정 할 때 처럼 Vertical spacing을 상위 뷰의 Bottom과의 간격 설정을 통해서 할 수 있습니다. 따라서 이번에는 고정 값으로 설정을 해주겠습니다.

고정된 Height 값을 설정하기 위해 Control + Drag를 자기 자신에게 합니다.

Height를 100으로 설정하면 Missing Constraints 경고가 하나 줄어들었을 것입니다.

남은 Missing Constraints또한 Trailing 을 통해서 MaxX Position은 정의가 되었지만, View의 Width 또는 Min X Point가 정의되어있지 않기 때문에 발생한 문제입니다.

그럼 추가한 View의 Leading을 Label의 Leading과 동일하게 해보겠습니다.

추가한 UIView의 최종 Constraints 설정

Label의 Leading과 동일하게 되어있기 때문에, Label의 Text 길이가 변경 될 때 동적으로 View의 Leading이 변하게 될 것입니다.

지금까지 설정한 것을 직접 확인해보면 다음과 같이 보입니다.

Constraint 설정 끝

위에서 동적으로 변한다고 한 것을 확인하고 싶은 분들이 있을 것 같아서 다음 코드도 추가했습니다.

...

private var textTimer : Timer? = nil
private var textFlag : Bool = false

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    print("Did Load")
    self.displayElementPosition()
    self.labelTextChangeWithDelay()
}

 .
 .
 .
 
private func labelTextChangeWithDelay() {
    if let _timer = self.textTimer {
        _timer.invalidate()
        self.textTimer = nil
    }
    let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (_timer) in
        self.lbText.text = self.textFlag ? "Text Test Label" : "Relative Text Change width test"
        self.textFlag = !self.textFlag
    }
    self.textTimer = timer
}

1초마다 Label의 text를 바꿔주는 코드입니다.

이 코드를 추가하고 실행하면 아래 Gif처럼 보입니다.

1초마다 반복됩니다!

 

3. 상세 설명

위에서 정의, 예제를 봤으니 이제 각 Constraint의 설정 값이 뭐가 있고 어떻게 쓰이는지 살펴보겠습니다.

 

 

 

 

 

 

 

 

 

 

 

Dannian의 블로그입니다.

 

 

본 포스팅은 학습 또는 정리를 목적으로 쓰인 글입니다.

내용 중 틀린 것이 있다면 댓글로 알려주시면 감사하겠습니다!

반응형