AutoLayout를 잡아보자

Duna·2021년 7월 22일
0
post-thumbnail

아요개발에서 가장 쉬우면서 가장 어려운 오토레이아웃🔥
오늘 오토레이아웃을 탈탈 털어보겠어요.


오토레이아웃을 잡는 방법은 아주 다양합니다.
스토리보드를 사용하는 방법도 있고, just 코드로만 잡는 방법도 있죠.


📐 Storyboard로 레이아웃 잡기


Storyboard로 레이아웃 잡는 것은 가장 기본적이고, 처음 Swift를 배울 때 다들 해봤을 겁니다.
컴포넌트를 놓고 top(위), bottom(아래), leading(왼), trailing(오)를 알맞게 배치를 하면 되는거죠!

컴포넌트를 그냥 놨는데도, 시뮬레이터에 잘 나오던걸요?

맞아요.

처음 UI 컴포넌트를 Storyboard에 올리면 빨간줄도 안뜨고 시뮬레이터에도 잘 뜰겁니다.

하지만, 해당 스토리보드가 base로 하고 있는 device 이외의 device로 바꿔서 run하면 우리가 놔둔 위치상으로 컴포넌트가 나오지 않을겁니다! 아마 안보이거나 잘못된 위치에 컴포넌트가 안착할겁니다.

그래서 우리는 AutoLayout를 잡는거예요!

AutoLayout를 잡게되면 어떤 device로 run하던간에 같은 위치에 컴포넌트가 자리를 잡거든요.

top, bottom, leading, trailing외에도

설정할 수 있는 Constraints나 priority등 AutoLayout를 통해서 잡을 수 있는 것들이 많습니다.

다양하게 잡아보는 연습을 하는 것도 좋은 거 같아요.


📐 Code로 레이아웃 잡기


Storyboard가 없어도 우리는 레이아웃을 잡을 수 있습니다.
코드로도 레이아웃을 잡을 수 있는 방식이 있기 때문이죠.

1️⃣ 라이브러리없이 Code로 레이아웃 잡기

라이브러리라는 건 cocoapod로 install해서 사용하는 레이아웃 라이브러리를 말합니다.
그런 라이브러리없이도 충분히 code로 레이아웃을 잡을 수 있어요.
해당 코드는 bottomView라는 UIView의 레이아웃을 잡는 코드입니다.

var bottomView = UIView()

override func viewDidLoad() {
	view.addSubview(bottomView)
	bottomView.translatesAutoresizingMaskIntoConstraints = false
	bottomView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
	bottomView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
	bottomView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
	bottomView.heightAnchor.constraint(equalToConstant: 35).isActive = true
}

코드를 보면 알 수 있듯
사용할 컴포넌트를 선언해주고,
해당 컴포넌트가 들어가길 원하는 곳에 addSubview해서 넣어준 후,
leading, trailing, bottom, height를 잡은 걸 볼 수 있어요.
저런 방식을 통해서 컴포넌트에 레이아웃을 코드로 잡아줄 수 있습니다.
하지만, 코드내에서 궁금한 점이 있을 거 같아요.

constraint함수 매개변수로 들어가는 게 매번 다른데, 각각 무슨 뜻일까요?

  • equalTo : 매개변수로 들어오는 부분과 맞닿게 constraint를 잡아요.
  • equalTo, constant : 매개변수로 들어오는 부분과 constant만큼 떨어진 곳에 constraint를 잡아요.
  • equalToConstant : 매개변수에 숫자를 넣어서 크기를 정해요.(height, width)
  • 해당 매개변수말고도 lessThan, GreaterThan 등이 있어서 다양하게 설정할 수 있어요.

isActive는 뭐죠?
저도 처음에 저 isActive가 뭔지 몰라서, 안쓰다가 큰 코 다쳤습니다.
layout코드를 잡게 되면 isActive가 없어도 에러가 안나는데, 대신 경고창이 하나 뜹니다.

분명 나는 쓴다고 썼는데, unused되는 코드라고 하네요. 이게 무슨 소리야!

isActive에 대해서 알아보러 갑시다.

Defaults to NO for newly created constraints.

새로 만들어진 constrains는 isActive가 no이기 때문에 기본적으로 unused됩니다. 따라서, isActive를 받아서 true로 만들어야 하는거죠.

각각 isActive하는 거 너무 코드 더럽히지 않나? 이런 생각이 들 수도 있어요. 그래서 단체로 isActive시키는 코드도 있습니다.

NSLayoutConstraint.activate([
	animationView!.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
  animationView!.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
  animationView!.widthAnchor.constraint(equalToConstant: 600),
  animationView!.heightAnchor.constraint(equalToConstant: 600),
])

이렇게 하면 한 번에 쏙 들어갑니다.


translatesAutoresizingMaskIntoConstraints = false

얘는 뭔데, false일까 하는 생각을 할 수 있습니다.

translatesAutoresizingMaskIntoConstraints는 view의 autoresizing mask가 AutoLayout Constraint로 변화되는지 여부를 결정하는 Bool값이에요.

true값을 넣어두게 된다면, "Xcode가 알아서 resizing 해줄게!" 라는 뜻이기 때문에 우리가 원하는 constraint를 사용하기 위해서는 false로 설정해서 "아니 알아서 할게^^;" 라고 전해줘야 해요.


func로 선언된 함수 안에서만 쓸 수 있는가?

답은 아니오.

우리는 해당 컴포넌트를 선언해줬을 때 바로 초기화해줄 수 있어요. 그 말을 곧 레이아웃도 초기화할 수 있다는 뜻입니다. 하지만 여러분은 문제에 봉착할 겁니다.

var toolBar: UIToolbar = {
	      let toolbar = UIToolbar()
        view.addSubview(toolbar)
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        toolbar.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 0).isActive = true
        toolbar.bottomAnchor.constraint(equalToSystemSpacingBelow: view.safeAreaLayoutGuide.bottomAnchor, multiplier: 0).isActive = true
        toolbar.trailingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.trailingAnchor, multiplier: 0).isActive = true
        return toolbar
}()

이런 코드를 쓰면 에러가 날 겁니다.

이유는 간단합니다. 처음 뷰가 생성될 때 toolBar가 쇽샥 생겨나는데, 아직 view의 위치도 제대로 잡히지 않은 혼란에 상태에서 toolBar도 함께 태어나기 때문에 레이아웃을 잡을 수 없는 상태인겁니다.

그럼 어떻게 해줘요?
조금 늦게 태어나라고 선언을 해주면 됩니다. 조금 늦게 view가 정돈되고 나서 와줘.
이렇게 토닥이는 친구가 lazy 속성입니다.

lazy var toolBar: UIToolbar = {
	      let toolbar = UIToolbar()
        view.addSubview(toolbar)
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        toolbar.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 0).isActive = true
        toolbar.bottomAnchor.constraint(equalToSystemSpacingBelow: view.safeAreaLayoutGuide.bottomAnchor, multiplier: 0).isActive = true
        toolbar.trailingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.trailingAnchor, multiplier: 0).isActive = true
        return toolbar
}()

이제 안에다가 레이아웃을 잡아줄 수 있어요.

하지만 이 안에서 레이아웃을 잡게 되면 다른 속성들과 함께 layout를 잡는 게 힘들기에 간단하게 view에 layout잡을 때만 사용해주세요.


2️⃣ 라이브러리 Code로 레이아웃 잡기

대표적인 레이아웃 라이브러리는 SnapKit입니다.

SnapKit은 정말 간편해요. 한 번 쓰고 나면 기본 Layout코드는 너무 길게 느껴질 겁니다.

보시다시피 엄청 짧아졌습니다.

SnapKit은 기본 Layout를 사용한 라이브러리인데, 귀찮게 우리가 해야하는 일들을 대신해주는 부분들이 많기 때문에 사용이 아주 편리해요.


📐 코드 or 스토리보드?


둘 중에 어느 것을 쓰는 게 더 좋다. 나쁘다. 이런건 없습니다.

훨씬 편한걸 사용하는 거죠.

물론 스토리보드의 경우에는 Storyboard가 너무 많아지면 뷰 속도가 많이 느려진다. 라는 말이 있지만, 꼭 그렇지만은 않다고 합니다. 스토리보드도 잘 조치를 취해준다면 코드로 레이아웃 쓴 것만큼의 기능을 한다는 거죠.

결론: 둘 다 써보자! 둘 다 어느정도 잘 사용할 수 있게 하자!

profile
더 멋진 iOS 개발자를 향해

0개의 댓글