본문 링크 (Original Link)

유동적 글자크기로 커스텀 폰트 사용하기

2017.08.23

# • #

by kharrison, translated by pilgwon

유동적 글자크기로 커스텀 폰트를 사용하는 것은 항상 가능헀지만 각 텍스트 스타일에 맞게 크기를 조정하는 데 있어서 약간의 노력이 필요했습니다. Apple은 새로운 폰트 메트릭 클래스를 iOS 11에 만들었고 그 클래스는 이 일을 덜 괴롭게 만들어 줄 것입니다.

유동적 글자크기

Apple은 iOS 7에서 시스템 세팅에 의해 유저가 원하는 글자 크기를 사용할 수 있도록 유동적 글자크기를 만들었습니다.

image1

유동적 글자크기를 레이블, 텍스트 필드 또는 텍스트 뷰에서 사용하려면 UIFont의 클래스 메소드인 preferredFont(forTextStyle:)를 사용해야 합니다. 이 함수를 통해 반환되는 폰트는 Apple San Francisco를 쓰는데, 사용자의 설정과 의도한 텍스트 스타일에 맞는 사이즈와 두께를 가지고 있습니다.

예를 들어, 바디 텍스트 스타일로 레이블을 만드는 코드는 아래와 같습니다.

let label = UILabel()
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true

메모:

아래 이미지는 엑스트라 스몰, 라지 그리고 엑스트라-엑스트라-엑스트라 라지일 경우의 사이즈들을 보여주는 이미지입니다.

image2

접근성에서 정한 사이즈에 따라 텍스트 스타일들의 크기가 어떻게 바뀌는지 기억해두십시오. 이것은 iOS 11에서의 새로운 기능입니다. 더 큰 접근성 사이즈가 처음 나왔을 때는 iOS 7이었고 .body 스타일에만 적용되었습니다.

커스텀 폰트 크기 조정하기

iOS 11이전에 커스텀 폰트의 유동적 글자크기를 지원하려면 당신은 폰트의 상세 정보(폰트 페이스와 사이즈)를 10가지의 스타일에 다 정해줘야 했고 12가지 컨텐츠 사이즈 카테고리에 따라 어떻게 크기를 조정할 지 정해야했습니다.

Apple은 그들이 San Francisco 타입페이스에 사용하는 폰트 메트릭을 iOS Human Interface에서 공개했습니다. 그리고 그것은 텍스트 스타일에 맞춰서 조정을 어떻게 해야하는지 정하는데 좋은 시작점이 되었습니다.

예를 들어, .headline 텍스트 스타일은 Semi-Bold 페이스를 사용하고 있고 라지 컨텐츠 사이즈일 때는 17포인트, 3X라지 컨텐츠 사이즈일때는 23 포인트를 사용합니다.

폰트 메트릭스

유동적 글자크기를 위해서 커스텀 폰트를 조정하는 일을 쉽게 하기 위해서 Apple은 iOS 11에서 UIFontMetrics를 소개합니다. 커스텀 폰트를 주어진 텍스트 스타일에 맞춰서 사용하려면 당신은 먼저 그 스타일을 위한 폰트 메트릭스를 구해야합니다.

이번에는 레이블에 .body 텍스트 스타일을 커스텀 폰트로 설정하는 예제를 봅시다. 가장 기본적인 접근 방식은 다음과 같습니다.

let font = UIFont(name: fontName, size: fontSize)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
label.font = fontMetrics.scaledFont(for: font)

당신은 커스텀 폰트와 사이즈를 통해 당신의 폰트를 만들었습니다. 이젠 .body 텍스트 스타일을 위한 폰트 메트릭스를 얻은 다음 유저의 설정에 맞게 폰트를 조정하기 위해 scaledFont(for:)를 사용합니다.

UIFontMetrics 클래스는 12가지의 컨텐츠 사이즈 카테고리를 위한 폰트의 정보(타입페이스와 사이즈)가 기입된 표의 필요성을 없애줍니다. 기본 컨텐츠 사이즈의 텍스트 스타일별로 어떤 폰트를 쓸 지 정하는 작업은 여전히 당신이 해야하는 작업입니다. 이 폰트 사이즈는 사용자가 컨텐츠 사이즈를 변경할 때 폰트 메트릭스에 따라 조정됩니다.

스타일 딕셔너리

코드에 폰트 이름과 사이즈가 흩어져 있는 끔찍한 경우를 피하기 위해서 저는 결국 폰트 이름과 사이즈가 .large 텍스트 스타일에 맞게 기록되어 있는 스타일 딕셔너리를 만들게 되었습니다. 커스터마이징과 폰트 변경의 용이함을 위해서 저는 이 스타일 딕셔너리를 plist 파일로 저장해두었습니다.

아래는 iOS에 Apple의 기본 번들인 Noteworthy 폰트의 경우입니다.

여기엔 볼드와 라이트 폰트일 경우가 저장되어 있습니다.

image3

저는 Apple이 각 스타일에 .large 텍스트 스타일로 사용하는 폰트 사이즈를 유지했습니다. 그래서, 예를 들어, 저는 17포인트짜리 Noteworthy-Bold를 .headline에 쓰고 17포인트짜리 Noteworthy-Light를 .body에 사용했습니다.

폰트를 적용하기 위해 저는 그 딕셔너리를 ScaledFont 유틸리티 클래스로 한 번 씌웠습니다. 이 유틸리티 클래스는 plist 파일로 초기화 할 수 있고 따로 익스텐션이 필요하지 않습니다.

그렇게 하면 font(forTextStyle:) 메소드는 각 텍스트 스타일에 맞게 조정된 폰트를 반환합니다.

public final class ScaledFont {
  public init(fontName: String)
  public func font(forTextStyle textStyle: UIFontTextStyle) -> UIFont
}

더 자세한 정보는 코드에서 확인할 수 있습니다. 하지만 여기에 텍스트 스타일에 맞는 폰트를 찾고 UIFontMetrics를 사용하여 조정된 폰트를 반환하는 흥미로운 메소드가 있습니다. 만약 스타일 딕셔너리가 텍스트 스타일에 대한 정보를 가지고 있지 않다면 Apple의 폰트 정보를 가져옵니다.

public func font(forTextStyle textStyle: UIFontTextStyle) -> UIFont {
    guard let fontDescription = styleDictionary?[textStyle.rawValue],
        let font = UIFont(name: fontDescription.fontName, size: fontDescription.fontSize) else {
            return UIFont.preferredFont(forTextStyle: textStyle)
    }

    let fontMetrics = UIFontMetrics(forTextStyle: textStyle)
    return fontMetrics.scaledFont(for: font)
}

이 메소드를 Noteworthy.plist와 쓰기 위해 뷰 컨트롤러에서 lazy를 사용하여 불러옵니다.

private let fontName = "Noteworthy"

private lazy var scaledFont: ScaledFont = {
    return ScaledFont(fontName: fontName)
}()

그리고 레이블을 위한 설정을 할 때는 font(forTextStyle:)을 호출합니다:

let label = UILabel()
label.font = scaledFont.font(forTextStyle: textStyle)
label.adjustsFontForContentSizeCategory = true

당신이 UIFontMetrics로 폰트 조정을 하는 한, adjustsFontForContentSizeCategory 속성은 여전히 작동할 것이고 당신은 유저가 설정을 변경했을 때 폰트 업데이트를 해야하는지에 대한 걱정을 하지 않아도 됩니다. 아래는 Noteworthy 폰트를 사용했을 때를 캡쳐한 것입니다.

image4

메모: 저는 이게 버그인지 기능인지 확신할 수 없지만, caption2.large사이즈에서 caption1보다 더 작은 폰트 사이즈를 사용하는데도 불구하고 caption2가 보기에 caption1보다 더 커 보입니다.

커스텀 폰트 사용하기

당신이 쓸 수 있는 폰트는 iOS에 포함된 폰트에만 제한되지 않습니다. 이것은 구글 폰트에서 다운로드 받은 NotoSans입니다. (당신의 앱에 다운로드받은 폰트를 넣는다면 라이센스를 꼭 확인하세요!) NotoSans는 레귤러, 볼드, 이탤릭, 그리고 볼드 이탤릭 페이스로 구분되어 있습니다. 저는 subheadline과 caption 스타일에 이탤릭을 사용했습니다:

image5

만약 당신이 커스텀 폰트를 다운로드 받아 당신의 프로젝트에 추가한다면 타켓과 Info.plist의 “Fonts provided by application” 리스트의 UIAppFonts키값에 추가하는 것을 잊지마십시오:

image6

사용하려는 폰트의 이름을 모르는 경우 아래의 코드 스니펫으로 사용 가능한 모든 폰트의 이름을 출력할 수 있습니다.

let families = UIFont.familyNames
families.sorted().forEach {
  print("\($0)")
  let names = UIFont.fontNames(forFamilyName: $0)
  print(names)
}

코드 보기

당신의 저의 GitHub 레포지토리의 CodeExamples에 있는 이 포스트를 위한 예제를 볼 수 있습니다:

더 읽을거리

유동적 글자크기에 WWDC 20177 세션을 보세요: