[iOS] Dynamic Type에 따른 AutoLayout 조정하기 (feat. WWDC 2017)
👨🏻‍💻iOS 공부/iOS & Swift

[iOS] Dynamic Type에 따른 AutoLayout 조정하기 (feat. WWDC 2017)

728x90
반응형

WWDC 2017 Building Apps with Dynamic Type를 보다가 마침 현재 프로젝트에도 있는 문제가 있어서 적용 가능해보이는 부분을 발견했다.

바로 UILabel이 나란히 2개 있는 상황에서 기기의 폰트 크기가 커짐에 따라 어떻게 레이아웃을 잡아야하는지에 대한 내용이었다.

당연히 텍스트 일부가 ...등으로 짤리면 안되고, 뭔가 텍스트의 줄바꿈이 이상하게 되어있어도 안된다고 이야기하고 있다. 딱 봐도 이상해보이긴 한다...

 

그래서 권장하는 방식은 텍스트 크기가 커졌을 때, 우측 UILabel을 좌측 UILabel 아래로 내리는 방법이다!

WWDC에서는 아래와 같은 방법으로 구현할 수 있다고 이야기하고 있다.

 


우측 UILabel의 firstBaseline을 좌측 UILabel lastBaseline에 맞추는데, 바로 아래 딱 붙게해줄 수 있도록 constriantEqualToSystemSpacingBelow를 주고 있는 것을 볼 수 있다.

 

근데 공식문서를 보면 아래와 같이 사용하고 있는 것 같다.

constraint(equalToSystemSpacingBelow:multiplier:)

괄호의 위치가 조금 다른 느낌...?

 

아무튼 이렇게 레이아웃을 주면 vertical하게 위치시킬 수 있다고 한다. 이제 어떻게 시스템 폰트 크기를 식별하느냐인데, 이 또한 WWDC에서 알려주고 있다.

두 가지 방법이 있는데, 하나는 isAccessibilityCategory를 사용하는 방법, 다른 하나는 특정 글자 크기를 지정해서 그걸 넘어서는지 확인하는 방법이다.

 

isAccessibilityCategory의 문서를 보면
accessibilityMedium, accessibilityLarge, accessibilityExtraLarge, accessibilityExtraExtraLargeaccessibilityExtraExtraExtraLarge 만 true의 값을 반환한다고 한다.

 

그래서 우선은 이를 활용해서 레이아웃을 따로 잡아주었다.

 

자 그러면 한 번 구현해보자!!

우선 레이아웃을 담아줄 변수를 생성하자.

var LargeFontTypeLayout: [NSLayoutConstraint]?
var standartFontTypeLayout: [NSLayoutConstraint]?

isAccessibilityCategory 여부에 따라 나뉘는 두 가지 케이스에 맞게 레이아웃을 잡아주기 위해 두 가지 레이아웃 배열을 만들어줬다.

 

각 케이스에서만 특수하게 적용해줄 레이아웃들을 각 배열에 담아준다. 공통으로 적용되는 레이아웃들은 굳이 배열에 담지 않고도 바로 적용시켜줘도 된다.

LargeFontTypeLayout = [
    second.firstBaselineAnchor.constraint(equalToSystemSpacingBelow: first.lastBaselineAnchor, multiplier: 1),
    second.leadingAnchor.constraint(equalTo: first.leadingAnchor)
]

standartFontTypeLayout = [
    second.centerYAnchor.constraint(equalTo: first.centerYAnchor), 
    second.leadingAnchor.constraint(equalTo: first.trailingAnchor, constant: 10)
]

자 이제 각 케이스에 따라 담아준 레이아웃 배열을 active시켜주면 된다.

if traitCollection.preferredContentSizeCategory.isAccessibilityCategory {
    LargeFontTypeLayout?.forEach {
        $0.isActive = true
    }
} else {
    standartFontTypeLayout?.forEach {
        $0.isActive = true
    }
}

자 여기까지 잡아준 레이아웃 코드를 메서드로 잘 정리해서 viewDidLoad()에 넣어주면 앱이 처음 실행되었을 때 기기의 폰트 크기에 따라 잘 분기가 될 것이다.

 

하지만 중간에 앱을 백그라운드로 보내고, 기기의 폰트 크기를 바꾸게 되면 현재 코드로서는 대응하지 못하게 된다.

 

그렇기에 추가해줘야하는 코드가 있는데, 바로 기기의 폰트 설정이 바뀌었다는 정보를 받기 위해 NotificationCenter에 addObserver를 해줘야 한다.

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(setLayoutByDynamicType), name: UIContentSizeCategory.didChangeNotification, object: nil)
}

// setLayoutByDynamicType
@objc func setLayoutByDynamicType() {
    if traitCollection.preferredContentSizeCategory.isAccessibilityCategory {
        standartFontTypeLayout?.forEach {
            $0.isActive = false
        }
        LargeFontTypeLayout?.forEach {
            $0.isActive = true
        }    
    } else {
        LargeFontTypeLayout?.forEach {
            $0.isActive = false
        }
        standartFontTypeLayout?.forEach {
            $0.isActive = true
        }
    }
}

시스템에서 폰트 카테고리가 바뀌었을 때 post를 주는데 그 채널은 UIContentSizeCategory.didChangeNotification이다. 이에 기본적으로 제공해주는 채널에 대해 addObserver를 해두고 알림을 받았을 때 실행할 메서드를 작성해준다.

 

다른 것은 없고 두 케이스의 레이아웃 배열을 스위치 온/오프 하듯이 원하지 않는 레이아웃을 deactive해주고, 원하는 레이아웃을 active해주면 된다.

 

자 이제 결과물을 확인해 볼 시간...!

 

Standard > Larger Text

 

 

Larger Text > Standard

이제 텍스트 크기에 맞게 레이아웃이 자동으로 적용되는 것을 볼 수 있다.

 

다 하고 알게된 사실인데... 만약 저 두 개의 UILabelUIStackView로 묶어도 되는 상황이라면 더 쉽게 해결해 볼 수 있다...

글자가 커지는 경우 .axisvertical로 바꿔주고, 기본인 경우 다시 horizontal로 바꿔주면 된다.

 

뿐만 아니라 필요하고, 필요하지 않는 레이아웃을 아까 봤던 방법처럼 active/deactive해서 적용해주면 더 간단하게 해결해 볼 수도 있을 것 같다.

 

끝!

 

 


Ref

 

https://developer.apple.com/videos/play/wwdc2017/245/

 

Building Apps with Dynamic Type - WWDC17 - Videos - Apple Developer

With Dynamic Type, people choose their preferred text size and iOS switches fonts automatically as needed. Understand why Dynamic Type is...

developer.apple.com

 

https://developer.apple.com/documentation/uikit/nslayoutyaxisanchor/2866022-constraint

 

Apple Developer Documentation

 

developer.apple.com

https://developer.apple.com/documentation/uikit/uicontentsizecategory/2897444-isaccessibilitycategory

 

Apple Developer Documentation

 

developer.apple.com

https://a11y-guidelines.orange.com/en/mobile/ios/wwdc/2017/245/

 

WWDC 2017 : Building Apps with Dynamic Type - Orange digital accessibility guidelines

WWDC 2017 : Building Apps with Dynamic Type This video available on the official Apple website (session 245) aims at defining what Dynamic Type is, based on good practice implementation. Various contents and their video timelapse are indicated hereunder: T

a11y-guidelines.orange.com

 

728x90
반응형