safeAreaInsets 변화에 대한 감지 방법들

iOS11

0

오늘 아침에 올린 iPhone X화면이 기존 아이폰들과는 달라짐에 따라 iPhone X 화면 구분하기란 타이틀로 글을 올렸다. 이 내용에는 간단하게 화면을 체크하는 방법만 소개했는데 좀더 구체적인 내용을 정리해보고자 남긴다.

Xcode 9부터 Safe Area라는 개념이 등장했다. safeAreaInsets자체는 view.safeAreaInsets를 통해 얻을 수 있지만, 화면 회전과 StateBar 표시/숨기기 등에 safeAreaInsets에 변경이 있을 경우 어떻게 감지하고 어떻게 처리면 좋을지를 정리해 본다.

safeAreaInsets 변경 감지하는 3가지 방법

UIView의 subclass

구현은 아래와 같이 UIView subclass를 생서앟고 func safeAreaInsetsDidChange()를 override하여 변경을 감지한다.

스토리보드의 Identity Inspector에서 ViewController의 view를 UIView에서 SafeAreaView로 변경한다.

이 방법을 이용하면 UIScrollView, UITableView등의 subclass를 모두 구현해야 한다.

UIView Extension

UIView extension에서 safeAreaInsets변경을 감지할 수 있다.

우선 Safe Area에 대한 extension을 네임스페이스에서 구별할 수 있도록 SafeAreaExtension을 만든다. 실제 사용은 var insetsDidChange: ((UIEdgeInsets) -> ())? {get set}이다.

UIView의 extension으로 SafeAreaExtension의 프로퍼티를 추가한다. insetsDidChange를 유지하고 싶기 때문에 SafeAreaExtension을 AssociatedObject하고 있다.

UIView.safeAreaInsetsDidChange()를 처리할 수 있도록  메소드 스위즈링(Method Swizzling)을 한다. safeAreaInsetsDidChange를 sa_safeAreaInsertsDidChange로 대체하여 원래 메소드를 호출한 후, 확장한 safeArea.insetDidChange를 호출하여 현재의 safeAreaInsets로 전달한다.

최근들어 사용하고 있는 AssociatedObject와 Method Swizzling을 이용하여 재미있다고 생각된다. 이번 Extension에 대해서는  Github에 공개하였다.

RxSwift 이용하기

Reactive를 확장하고 methodInvoked를 이용하여 safeAreaInsetsDidChange 호출을 감시한다. 메소드가 호출되면, base.safeAreaInsets를 Observable<UIEdgeInsets>.just()을 한다.

그외

소스코드에서 AutoLayout을 이용하여 Safe Area를 대응할수도 있다. 예로 어떤 view를  superview의 상하좌우에 safeArea를 고려하여 addSubview를 구현한다고 생각해 보자.

NSLayoutConstraint를 이용한다면, view.safeAreaLayoutGuide를 item 또는 toItem으로 전달하여 구현할 수 있다.

위 내용을 NSLayerAnchor를 이용한다면 아래와 같다.

 

Facebook Comments

No more articles