ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Get started with Dynamic Type (feat. WWDC 2024)
    iOS 2024. 8. 26. 19:10

    안녕하세요. 그린입니다 🍏

    이번 포스팅에서는 다이나믹 타입에 대해 WWDC 2024에서 나온 세션을 학습해보겠습니다 🙋🏻

     

    Dynamic Type은 사용자가 시스템 전반과 모든 앱에서 원하는 텍스트 크기를 선택할 수 있는 기능이죠 😃

    이번 포스팅에서는 주로 이 다이나믹 타입이 어떻게 작동하며, 텍스트 크기 같은 것들을 어떻게 식별하고 조절을 하는지를 중점적으로 알아봅니다.

     

    한번 시작해볼까요?

     


    Get started with Dynamic Type


    Introduction

    동적 UI를 만들면 화면 크기와 방향, 플랫폼에 상관없이 동작하는 인터페이스를 구축할 수가 있죠.

    사용자마다 선호하거나 필요한 텍스트 크기가 다르기 때문에 동적 UI는 중요한 부분입니다.

     

     

    다이나믹 타입은 모든 텍스트 크기에서 가독성을 높여줄 수 있습니다.

    즉, 사용자가 필요에 맞게 옵션으로 텍스트 크기를 변경할 수 있죠.

    설정은 아주 쉽게 설정의 손쉬운 사용에서 변경할 수 있습니다 😁

     

     

    기본적으론 7가지 텍스트 크기 중 선택할 수 있죠.

    여기서 Larger 옵션을 활성화하면 5가지 크기가 더 추가됩니다.

     

    매번 이렇게 설정까지 들어와서 조정하기 번거롭다면, 제어 센터에 텍스트 크기 제어 항목을 추가해 사용할 수도 있습니다.

     

    기본적으로는 텍스트는 Large가 디폴트로 되어 있어요.

    텍스트 크기 변경은 적용시키면 바로 전체 반영됩니다.

     

     

    만약 텍스트 사이즈가 커져 넘쳐나게 되면 당연하게 스크롤이 지원되어 모두 제공 가능해지죠.

     

    여기까지가 다들 워낙 잘 알고 있다고 생각되는 다이나믹 타입에 대한 소개였습니다.

     

    이제 본격적으로 다이나믹 타입으로 앱의 컨텐츠 크기를 조절하고 제공하는 기법에 대해 몇가지 다뤄볼까요?

     


    Scaled text

    가장 먼저, 텍스트 크기 조절 방법부터 살펴보겠습니다.

    다이나믹 타입을 적용하려면 우선 가장 먼저는 앱이 시스템에서 제공하는 텍스트 스타일 중 하나를 선택해보는것입니다.

    즉, 내장 텍스트 스타일을 사용해보는거죠.

     

    물론, 커스텀 폰트에 대해서도 다이나믹 타입을 적용해줄 수 있지만, 부수 작업들이 필요하니 해당 포스팅에서는 다루지 않고 별도 포스팅으로 커스텀 폰트에 대해 SwiftUI와 UIKit에서 어떻게 다이나믹 타입을 적용하는지를 따로 정리해보겠습니다 🙋🏻

     

    그래서 다시 본론으로 돌아오면

     

     

    SwiftUI에선 이렇게 font 모디파이어를 이용해줄 수 있죠.

     

     

    UIKit에선 adjustsFontForContentSizeCategory 속성을 true로 설정해 시스템의 텍스트 크기에 따라 자동으로 변경되도록 지정할 수 있습니다.

    그리고, preferredFont를 통해 폰트를 설정하죠.

     

    다이나믹 타입을 사용할때 주의할 부분은, 큰 텍스트로 변환해서 표시할 텍스트 줄이 부족하면 짤리거나 말줄임이 될 수 있습니다.

    이런 부분은 Xcode에서 프리뷰를 통해 미연에 방지해볼 수 있습니다.

     

     

    Dynamic Type Variants를 통해 전체 다이나믹 타입에 대해 한번에 볼 수 도 있고, 캔버스에서 설정 버튼을 통해 특정한 다이나믹 타입을 조정할 수도 있습니다.

     

     

    또한, Xcode 디버거를 사용해도 텍스트 크기를 테스트할 수 있으며, Accessibility Inspector를 이용해 접근성으로 테스트해볼 수도 있죠.

     

     

    그럼 이제, 확연히 어디서 어떻게 표현되는지 짤리는지 사전에 알 수 있겠죠?

     


    Dynamic layouts

    시스템 폰트와 텍스트 스타일을 사용하는건 다이나믹 타입을 시작하는데 아주 방법이죠.

    큰 텍스트에 따라서 콘텐츠 레이아웃 조정도 고려할 수 있습니다.

     

     

    이렇게 아래 포스터를 선택하는 부분을 보면, 텍스트 크기에 따라 가로로 다 표현할 수 없는 레이아웃에선 우측과 같이 세로 스택으로 전환할 수 있습니다.

     

    SwiftUI를 예시로 들어볼께요.

    바로 DynamicTypeSize를 이용해 동적인 레이아웃을 컨트롤할 수 있습니다.

     

     

    이렇게 환경 변수로 DynamicTypeSize를 이용하고 AnyLayout 타입의 프로퍼티를 두는것이죠.

    즉, 텍스트 크기에 따라 VStack으로 보여줄지 HStack으로 보여줄지를 결정하고 body에선 해당 AnyLayout 프로퍼티로 감싸면 되는것입니다.

     

    셀에서 뿐만 아니라, 이 셀을 전체적으로 보여주는 리스트에서도 동일하게 설정할 수 있죠.

     

     

    이제 그러면 아래처럼 동적으로 텍스트 크기에 맞춰 레이아웃이 자연스럽게 보여집니다.

     

     

    간단하죠?

     

    UIKit에선 UIStackView를 사용해 축을 결정해줄 수 있는데요.

    axis에 적용시켜주면 됩니다.

     

    if traitCollection.preferredContentSizeCategory.isAccessibilityCategory { 
      stackView.axis = .vertical 
    } else { 
      stackView.axis = .horizontal 
    }

     

    이런 예시의 코드를 볼 수 있죠.

     

    앱이 실행되는 동안에 텍스트 크기 변경에 반응해주려면, UIContentSizeCategory 노티피케이션을 통해 제공해줄 수 있습니다.

     

    NotificationCenter.default.addObserver(
      self, 
      selector: #selector(contentSizeCategoryDidChange), 
      name: UIContentSizeCategory.didChangeNotification, 
      object: nil
    )
    
    func updateStackViewAxis() {
      if traitCollection.preferredContentSizeCategory.isAccessibilityCategory {
        stackView.axis = .vertical
      } else {
        stackView.axis = .horizontal
      }
    }

     

    이런식으로 할 수 있겠죠?

     


    Images and symbols

    더 큰 텍스트를 사용할 때 레이아웃은 물론 텍스트 콘텐츠와 함께 표시되는 이미지와 심볼도 조절해볼 수 있어야 합니다.

     

     

    아이폰의 설정 앱을 보면 이렇게 텍스트는 커져도 아이콘은 커지지 않는걸 볼 수 있어요.

    이건, 앱이 심볼보다 필수 컨텐츠의 크기 조절을 우선적으로 처리하기 때문입니다.

     

    이미지 크기가 조절되지 않는 경우 텍스트는 최대 공간을 사용하려고 이미지 아래로 줄바꿈을하죠.

    Off 처럼 말입니다.

     

    즉, 해당 심볼이 커지는것이 아니라 심볼 아래 영역으로 컨텐츠가 줄바꿈되어 차지하는것을 볼 수 있죠 😃

     

    SwiftUI에선 텍스트가 아이콘 아래로 줄바꿈하는것은 간단합니다.

    List를 이용하면 별도 작업없이도 가능합니다.

     

     

    UIKit을 이용한다면, NSAttributedString을 통해 구현해줘야 합니다.

     

     

    NSTextAttachment로 이미지와 함께 속성이 지정된 문자열을 생성하고, 이를 속성이 지정된 문자열에 추가해야 합니다.

     

    물론, 이미지 크기를 조절하고 싶을 수도 있죠.

    이미지가 SF Symbol이면 자동으로 크기가 조절됩니다.

    그러나, 에셋을 통해 이미지를 제공한다면 (즉, 이미지 에셋을 사용하고 있어 PDF, JPG, PNG 등등으로 제공한다면) ScaledMetric API를 이용해야 합니다.

     

     

    해당 값은 텍스트 크기가 변경되면 런타임에서 자동으로 조절이 됩니다.

     

    UIKit에선 UIImage SymbolConfiguration을 통해 구현할 수 있습니다.

     

    let imageConfiguration = UIImage.symbolConfiguration(textStyle: .body)
    let image = UIImage(systemName: systemImageName, withConfiguration: imageConfiguration)

     

    요런식으로 말이죠.

     

    이제 마지막으로 큰 컨텐츠 뷰어를 살펴보겠습니다 😃

     


    Large content viewer

    큰 컨텐츠 뷰어를 사용하면 글자가 커졌을 때 커지지 않는 제어 항목을 탐색할 수 있어요.

    생소할 수 있는데 그림으로 먼저 보시죠!

     

     

    이렇게 하단 탭바가 존재하는데, 해당 탭바 아이템의 항목은 커지지 않았죠.

    그치만 크게 보고 싶다면 해당 탭 아이템을 누른채로 드래그를 하면 큰 컨텐츠 뷰어가 중앙에 나타나는걸 볼 수 있습니다.

     

    물론, 이 탭바를 키울수도 있었겠지만 애플이 말하길 아래와 같이 텍스트에 따라 탭바도 커지면 거의 화면 1/4를 차지합니다.

    즉, 중점적으로 컨텐츠를 보여줘야하는데 컨텐츠는 잘 안보이게 되는것이기에 사용성이 떨어지죠.

     

     

    그래서, 이런 부분까지 확대를 시키지 않고 라지 컨텐츠 뷰어 기능을 제공하는것입니다.

    이 뷰어는 기본적으로 제공되는 Tab bars, Status bar, Navigation bars, Tool bars를 사용하면 자동으로 제공되기에 별도 해줄게 없습니다.

     

    다만, 커스텀하게 직접 만들어 사용한다면 해당 뷰어 채택을 고려해야 합니다.

     

    SwiftUI에서는 accessibilityShowsLargeContentViewer 모디파이어를 통해 채택할 수 있어요.

     

     

    이러면 버튼의 이름과 기호가 뷰어에 레이블로 표시되겠죠?

     

    UIKit에서는 먼저 UILargeContentViewerItem 프로토콜을 따라, 일련의 과정들을 구현해야 합니다.

    코드로 볼까요?

     

    import UIKit
    
    class ViewController: UIViewController {
      override func viewDidLoad() {
        super.viewDidLoad()
        setupLargeContentViewer()
      }
      
      func setupLargeContentViewer() {
        // 버튼 생성
        let button = UIButton(type: .system)
        button.setTitle("Large Content Button", for: .normal)
        button.frame = CGRect(x: 100, y: 100, width: 200, height: 50)
        view.addSubview(button)
        
        // UILargeContentViewerItem 프로토콜 구현
        button.showsLargeContentViewer = true
        button.largeContentTitle = "Large Button"
        button.largeContentImage = UIImage(systemName: "star.fill")
        
        // 제스처 인식기 추가
        let interaction = UILargeContentViewerInteraction(delegate: self)
        button.addInteraction(interaction)
      }
    }
    
    extension ViewController: UILargeContentViewerInteractionDelegate {
      func largeContentViewerItem(for interaction: UILargeContentViewerInteraction, defaultAction: UILargeContentViewerInteraction.Action) -> UILargeContentViewerItem? {
        // 현재 포커스된 뷰가 UILargeContentViewerItem을 구현했는지 확인
        guard let focusedView = interaction.focusedItem as? UILargeContentViewerItem else {
          return nil
        }
        return focusedView
      }
    }

     

    버튼 하나에 대한 예시로 라지 컨텐츠 뷰어를 만드는 샘플 코드입니다.

     

    이런식으로, 뷰어를 커스텀하게도 만들고 보여줄 수 있죠 😃

     


    마무리

    이제 다이나믹 타입에 대해 잘 살펴보고 학습해봤으니, 앱의 접근성을 끌어올리기 위해 테스트하고 적용해보면 어떨까요? 😁

     


    레퍼런스

     

    Dynamic Type 시작하기 - WWDC24 - 비디오 - Apple Developer

    Dynamic Type은 사용자가 시스템 전반과 모든 앱에서 원하는 텍스트 크기를 선택할 수 있는 기능입니다. Dynamic Type 지원을 시작하기 위해 Dynamic Type의 작동 방식, 앱 내 텍스트 크기 조절과 관련된 문

    developer.apple.com

    'iOS' 카테고리의 다른 글

    Meet the Contact Access Button (feat. WWDC 2024)  (3) 2024.09.05
    Custom Font Dynamic Type  (6) 2024.09.02
    UIScrollView의 contentInsetAdjustmentBehavior  (76) 2024.07.18
    View Snapshot Capture  (55) 2024.06.18
    Haptic Feedback  (58) 2024.06.11
Designed by Tistory.