1 분 소요

서론

HIG에 따르면 디바이스 자체의 글자 크기를 바꾸면 앱의 폰트 사이즈도 동적으로 바뀌게 해야한다. 그래서 우리는 .body와 같은 시스템 폰트 사이즈를 활용한다. 하지만 커스텀 폰트 사이즈를 다이나믹하게 바뀌도록 하고싶을때는 어떤 방법을 사용해야할까?

Font 구조 탐구

.body를 살펴보면 아래와 같이 Font extension에 포함되어 있다.

코드 구성과 문제점

따라서 우리의 custom font style 도 font extension 에 추가하면 된다는 말이다. 그래서 코드를 구성해보면 다음과 같다.

import SwiftUI

extension Font {
    static var customBody: Font {
        let defaultBodySize = UIFont.preferredFont(forTextStyle: .body).pointSize
        let preferredSize = UIApplication.shared.preferredContentSizeCategory

        switch preferredSize {
        case .extraSmall, .small, .medium:
            return .system(size: defaultBodySize)
        case .large:
            return .system(size: defaultBodySize)
        case .extraLarge:
            return .system(size: defaultBodySize + 1)
        case .extraExtraLarge:
            return .system(size: defaultBodySize + 2)
        case .extraExtraExtraLarge:
            return .system(size: defaultBodySize + 3)
        default:
            return .body
        }
    }
}

.body의 pointSize를 받아오고 그것에 맞춰 상대적인 사이즈를 입력해서 적용하는 방식이다. 이렇게 하면 아래와 같이 뷰에서 이질감 없이 custom font style을 적용시킬 수 있다.

        Text("Example Text")
            .font(.customBody)

하지만 이 방식에는 한가지 문제점이 있다. 앱을 실행한 상태에서 디바이스의 설정을 변경하면 앱에서는 바로 적용이 되지 않고 앱을 종료했다가 다시 켜야 적용이 된다는 점이다. 그 이유는 디바이스의 설정된 컨텐츠 사이즈 값을 컴파일 하는 시점에서 받아오기 때문인데 그 과정에서 사용하는 preferredContentSizeCategory가 앱 전체에 대한 컨텐츠 사이즈를 받아오기 때문이다. 별거 아닌 문제라고 생각할수도 있지만 찝찝하니까 이것을 해결해보자.

해결책과 완성된 코드

검색한 결과 @Environment(\.sizeCategory) var sizeCategory를 이용하면 현재 view의 컨텐츠 사이즈를 실시간으로 받아올 수 있었다. 조금 더 swiftUI 스러운(?) 방법이었다. 따라서 sizeCategory를 전달받을 수 있게 함수 형태로 수정하여 다음과 같이 코드를 작성하였다.

extension Font {
    static func customBody(for sizeCategory: ContentSizeCategory) -> Font {
        let defaultBodySize = UIFont.preferredFont(forTextStyle: .body).pointSize

        switch sizeCategory {
        case .extraSmall, .small, .medium:
            return .system(size: defaultBodySize)
        case .large:
            return .system(size: defaultBodySize)
        case .extraLarge:
            return .system(size: defaultBodySize + 1)
        case .extraExtraLarge:
            return .system(size: defaultBodySize + 2)
        case .extraExtraExtraLarge:
            return .system(size: defaultBodySize + 3)
        default:
            return .body
        }
    }
}
struct ContentView: View {
    @Environment(\.sizeCategory) var sizeCategory

    var body: some View {
        VStack{
            Text("Default body size")
                .font(.body)
            Text("Custom body size")
                .font(.customBody(for: sizeCategory))
        }
    }
}

이런식으로 적용하면 HIG 기준에 부합하며 폰트 사이즈에 대한 디자인적 요구사항을 충족시킬 수 있다.

댓글남기기