Get Started with Dynamic Type - WWDC24

Peter Yaacoub •


Introduction

Dynamic Type is a crucial feature for enhancing readability and accessibility in your apps. This article will guide you through the key concepts and best practices for implementing Dynamic Type in both SwiftUI and UIKit, based on the WWDC24 session.

Text

Apple recommends using their built-in font styles instead of fixed fonts to ensure optimal readability and scalability.

SwiftUI

Use the font(_:) view modifier to apply dynamic text styles.

Text("Hello, World!")
    .font(.title)

UIKit

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

Avoid fixed numbers of lines or fixed-size views to prevent text truncation or clipping issues.

Layout

Using dynamic layouts ensures that your UI adapts seamlessly to different text sizes.

SwiftUI

Use the dynamicTypeSize environment key to create an AnyLayout property that switches between HStackLayout and VStackLayout based on accessibility size.

@Environment(\.dynamicTypeSize) var dynamicTypeSize

let layout: AnyLayout = dynamicTypeSize.isAccessibilitySize ? AnyLayout(VStackLayout()) : AnyLayout(HStackLayout())

layout {
    Text("Dynamic")
    Text("Layout")
}

UIKit

Use UIStackView with the axis adjusted based on the accessibility category, and respond to content size change notifications.

let stackView = UIStackView()
stackView.axis = .vertical // Change based on content size category

NotificationCenter.default.addObserver(forName: UIContentSizeCategory.didChangeNotification, object: nil, queue: .main) { _ in
    stackView.axis = (UIApplication.shared.preferredContentSizeCategory == .accessibilityLarge) ? .vertical : .horizontal
}

Images

Prioritize scaling essential views over decorative ones, and consider removing non-essential decorative views for better readability and usability.

SwiftUI

Use the ScaledMetric property wrapper to scale image dimensions.

@ScaledMetric var imageSize: CGFloat = 100

Image(systemName: "star.fill")
    .frame(width: imageSize, height: imageSize)

UIKit

Use UIImage.SymbolConfiguration for scalable image dimensions.

let image = UIImage(systemName: "star.fill", withConfiguration: UIImage.SymbolConfiguration(scale: .large))

Custom Bars and Views

Adopt the large content viewer for custom bars and views to enhance accessibility.

SwiftUI

Use the accessibilityShowsLargeContentViewer() view modifier.

Example Code Snippet:

Button("Custom Button") {}
    .accessibilityShowsLargeContentViewer()

UIKit

Implement UILargeContentViewerItem, UILargeContentViewerInteraction, and use gestureRecognizerForExclusionRelationship, but I can’t find documentation for the latter.

Testing Accessibility

Always test your app with different Dynamic Type settings to ensure a full and acceptable user experience.

Conclusion

Implementing Dynamic Type in your app ensures that it remains accessible and user-friendly for all users, regardless of their preferred text size. By following the guidelines and best practices outlined above, you can create an app that adapts seamlessly to different accessibility needs.