오늘은 자주 보았지만 알쏭달쏭 헷갈리고 궁금한 내용이 있어 정리를 해보려합니다.

바로 safeAreaLayoutGuide vs safeAreaInsets 입니다.

둘이 좀 비슷하게 생겼고 .. 둘 다 UIView의 instance property라서 쉽게 목격할 수 있습니다.

그러면 어떤 차이점이 있고, 어떤 상황에서 사용할까요?

궁금해졌으니 알아봐야죠? 출발하시죠! 🏃🏻


SafeArea

차이를 알아보려면 먼저 공통 키워드인 safe area를 알아보겠습니다.

Apple에서 정의하는 safe area는 상단 Status bar와 하단 TabBar 영역을 제외한 영역을 safe area로 지칭하며, UI를 배치하는데 도움을 주는 영역이라고 합니다.

safe area는 상단 Notch가 생기면서 생긴 개념인데요,

상단 Notch가 없을 때에는 UILayoutGuide인 Top, Bottom LayoutGuide만으로도 NavigationBar 혹은 TabBar로 인한 View 배치에 영향이 없게 할 수 있었습니다.

UILayoutGuide

그러면 또 UILayoutGuide는 무엇이냐 ..!!!
단어 그대로 Layout을 위한 Guide라고 생각해주시면 될 것 같습니다.

실제 정의도 Auto Layout과 intreact할 수 있는 rectangular area거든요.

위와같이 NavigationBar 혹은 TabBar로 인한 영역 때문에 View가 가려지지 않게 배치하려면, Top/BottomLayoutGuide 까지 View를 배치하면 됬겠죠?

iPhone with TouchIDiPhone with FaceID

iOS 11이 등장하면서 상단 Notch가 생기고, Top/BottomLayoutGuide로는 충족되지 않는 영역이 존재하게 됩니다.

landscapeLeftlandscapeRight

TopLayoutGuide 로 잘 제한되었던 Notch 영역이 Landscape일 때는 침범하게 되었습니다.
따라서 새롭게 View를 배치할 영역을 지정해야 했고, 그에따라 safeAreaLayoutGuide이 생기게 되었습니다.

safeAreaLayoutGuide

직접 확인해보면 확실히 알겠죠?

portrait

iPhone with TouchIDiPhone with FaceID

landscapeRight

iPhone with TouchIDiPhone with FaceID

layoutMarginsGuide

그럼 다음으로 넘어가서 비스무리한 layoutMarginsGuide입니다.

동일하게 UILayoutGuide Type인것과 정의로 미루어보아 view를 배치할 때 도움이 되는 녀석일 것 같습니다.

위에서 직접 보았듯이 safeAreaLayoutGuide보다 portrait/landscape 상황에서의 좌/우 여백이 있습니다.

왜 있는거고, 어떤 상황에서 쓰일까요? 🧐

On iOS, what are the differences between margins, edge insets, content insets, alignment rects, layout margins, anchors...?

이곳에서 답을 얻을 수 있었는데요, layoutMarginsGuide는 View가 가지고 있는 임의의 area이며, margin을 가진 area이기 때문에 anchor를 사용하여 쉽게 margin을 나타낼 수 있다고 합니다.

즉 아래처럼 사용이 가능하다는것인데요

someButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8)

//can replace code with below

someButton.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor)

그렇다면 정말 8만큼의 여백이 있을까요?

let outer = UIView()
outer.layer.borderWidth = 1
outer.layer.borderColor = UIColor.blue.cgColor
view.addSubview(outer)
outer.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    outer.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    outer.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    outer.heightAnchor.constraint(equalToConstant: 100),
    outer.widthAnchor.constraint(equalToConstant: 100)
])

let inner = UIView()
inner.backgroundColor = .red
outer.addSubview(inner)
inner.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    inner.leadingAnchor.constraint(equalTo: outer.leadingAnchor),
    inner.trailingAnchor.constraint(equalTo: outer.trailingAnchor),
    inner.topAnchor.constraint(equalTo: outer.topAnchor),
    inner.bottomAnchor.constraint(equalTo: outer.bottomAnchor)
])

실제로 View를 만들고 딱 맞게 위치시켜보았습니다.
이제, layoutMarginsGuide로 anchor를 바꾸어보면..

NSLayoutConstraint.activate([
    inner.leadingAnchor.constraint(equalTo: outer.layoutMarginsGuide.leadingAnchor),
    inner.trailingAnchor.constraint(equalTo: outer.layoutMarginsGuide.trailingAnchor),
    inner.topAnchor.constraint(equalTo: outer.layoutMarginsGuide.topAnchor),
    inner.bottomAnchor.constraint(equalTo: outer.layoutMarginsGuide.bottomAnchor)
])

정말 여백이 생겼네요 ;;;
그러면 진짜 딱 8일까요..?

NSLayoutConstraint.activate([
    inner.leadingAnchor.constraint(equalTo: outer.leadingAnchor, constant: 8),
    inner.trailingAnchor.constraint(equalTo: outer.layoutMarginsGuide.trailingAnchor),
    inner.topAnchor.constraint(equalTo: outer.layoutMarginsGuide.topAnchor),
    inner.bottomAnchor.constraint(equalTo: outer.layoutMarginsGuide.bottomAnchor)
])

진짜 안믿기시겠지만.. 딱 맞습니다 ;; (못믿겠으시면 직접해보시길…)

그러면 왜왜왜 딱 8만큼의 여백이여야 할까요?
document는 모든것을 알고이따 ..

layoutMarginsGuide의 아래쪽에 layoutMarigns가 있네요?

layoutMargins

우선 documentation의 일부만 발췌하였습니다.

그 중엔 힌트가 될만한 내용이 있네요.

iOS11 이후부터는 directionalLayoutMargins property를 layout에 대한 margins을 설정할 때 해당 property 대신 사용하라고 가이드 하고있네여.

그럼 directionalLayoutMargins 넌또 뭔데;

directionalLayoutMargins

마찬가지로 일부만 발췌했습니다.

directionalLayoutMargins는 view안에 content를 layout할 때 사용하는 defaultSpacing이라고 합니다.

찾았다 요뇨속

그러면 기본값이 뭔데 !!

For most views, the default layout margins are 8 points on each side.

대부분의 View는 default layout marigns인 8 point를 각 side마다 가지고 있습니다.

오.. 진짜 뻥안치고 처음알았습니다. 각 뷰마다 기본으로 8의 여백을 가지고있는 LayoutGuide를 가지고 있군요 ;;

그러면 safeAreaLayoutGuide보다 8point만큼 작았던걸까요?
궁금한건 못참지

또 그건 아니네여; 16의 여백을 가지고 있습니다 머쓱;

그래도 이제는 safeAreaLayoutGuide / layoutGuideMargins의 차이는 똑바로 알겠네요~

아 추가로 safeArea하면 자동완성되는 하나의 property가 더 있는데요, safeAreaInsets

요녀석은 뭐하는 뇨속일까요

SafeAreaInsets

view의 safe area에 대한 inset을 나타낸다고 하네요.

그러면 아까 봤던 사진을 다시 가져와보면..

iPhone with FaceID(portrait)iPhone with FaceID(landscapeRight)

safe area에 대한 inset이면, portrait에서는 top/bottom, landscape에서는 left/right/bottom 을 가지겠군요

직접 확인해봅시다.

예상대로 나오는군요 😎

그럼 요녀석으로 뭘 할 수 있을까요?

portrait상태에서의 Notch의 height을 구할 때는 safeAreaInset의 top 을 활용해볼 수 있겠네요.

마찬가지로 bottom 영역의 safeArea height을 구할 때에는 bottom inset값을 활용해볼 수 있겠네요!

If the view is not currently installed in a view hierarchy, or is not yet visible onscreen, the edge insets in this property are 0.

추가로 documentation을 보다보니까, safeAreaInsets은 View가 install되기 전과 screen에 노출되지 않을때에는 0이라고 합니다.

즉 viewDidLoad에서는 view가 아직 layout되지 않았으니 safeAreaInsets은 모두 0이 나오게 됩니다.

사용하실 때 주의하세요~


마치며

단순히 자동완성때 이것저것 나오는것 때문에 너는 모하는녀석이냐..? 라는 호기심 때문에 파봤는데..
처음보는 내용도 있어서 재밌네요.

요즘은 SwiftUI로 대부분 UI를 만들지만, 어쨌든 UIView를 사용하긴 하니 놓을 순 없겠죠.

역시 공부에는 끝이 없습니다. 또한번 느끼게되네요.

오늘 알게된 내용들은 조금 오래 기억에 남았으면 좋겠네요!

읽어주셔서 감사합니다 🙇🏻‍♂️

참고자료

profile
hello, iOS

0개의 댓글