Dynamic Type là tính năng tích hợp sẵn của iOS tự động thay đổi kích thước phông chữ trong ứng dụng theo cài đặt hệ thống của người dùng. Người dùng đặt kích thước văn bản ưa thích trong Cài đặt → Màn hình và Độ sáng → Cỡ chữ, và tất cả ứng dụng hỗ trợ Dynamic Type đều thích ứng mà không cần thao tác thêm. Theo Apple Human Interface Guidelines, 2024, hỗ trợ Dynamic Type là yêu cầu bắt buộc để xuất bản trên App Store, vì đây là yếu tố cơ bản của khả năng tiếp cận trên nền tảng iOS.
Điểm chính
Dynamic Type là công nghệ iOS được giới thiệu trong iOS 7, cho phép văn bản trong ứng dụng tự động điều chỉnh theo cài đặt kích thước phông chữ hệ thống. Người dùng có thể tăng hoặc giảm phông chữ trong tất cả ứng dụng cùng một lúc — mà không cần thay đổi cài đặt trong từng ứng dụng riêng lẻ.
Theo Apple WWDC 2023, “Make Your App Visually Accessible”, hơn 40% người dùng iOS thay đổi kích thước phông chữ so với mặc định. Đối với nhóm tuổi 65+, con số này lên tới 70%. Dynamic Type là yêu cầu bắt buộc để chứng nhận khả năng tiếp cận của App Store. Thiếu hỗ trợ là lý do từ chối ứng dụng trong quá trình xem xét.
Cách hoạt động: ứng dụng sử dụng UIFont.preferredFont(forTextStyle:) thay vì UIFont(name:size:). iOS tự động trả về phông chữ được co giãn theo cài đặt hệ thống hiện tại. Khi kích thước thay đổi trong cài đặt, iOS tạo ra UIContentSizeCategory.didChangeNotification — ứng dụng phải tính toán lại bố cục.
Dynamic Type xuất hiện trong iOS 7 cùng với thiết kế phẳng. iOS 10 đã thêm hỗ trợ phông chữ tùy chỉnh thông qua UIFontMetrics. iOS 11 giới thiệu các cấp độ tiếp cận (lên tới AccessibilityXXXL). iOS 15 thêm Dynamic Type trong SwiftUI với hỗ trợ tự động. Mỗi bản phát hành, Apple lại thắt chặt các yêu cầu: bắt đầu từ iOS 17, các ứng dụng không hỗ trợ Dynamic Type sẽ nhận được cảnh báo khi tải lên App Store Connect.
iOS cung cấp 8 kiểu văn bản, mỗi kiểu có kích thước và đậm nhẹ được xác định trước cho cài đặt mặc định:
| Kiểu | Hằng số | Kích thước (L) | Mục đích |
|---|---|---|---|
| Large Title | .largeTitle | 34px | Tiêu đề chính của màn hình |
| Title 1 | .title1 | 28px | Tiêu đề phần |
| Title 2 | .title2 | 22px | Tiêu đề phụ |
| Title 3 | .title3 | 20px | Tiêu đề thẻ |
| Headline | .headline | 17px (đậm) | Chữ đậm để nhấn mạnh |
| Body | .body | 17px | Văn bản chính |
| Callout | .callout | 16px | Văn bản bổ trợ |
| Caption 1 | .caption1 | 12px | Chú thích hình ảnh |
| Caption 2 | .caption2 | 11px | Chú thích nhỏ |
| Footnote | .footnote | 13px | Chú thích cuối trang |
Sử dụng đúng kiểu không chỉ là vấn đề về “hình thức”. UIFont.TextStyle.body ở chế độ AccessibilityXXXL có thể đạt tới 53px. Nếu ứng dụng sử dụng phông chữ cố định 17px cho body, văn bản sẽ không đọc được đối với người dùng đã tăng cỡ chữ.
Dynamic Type không chỉ co giãn — nó duy trì phân cấp trực quan. Large Title luôn lớn hơn Title 1, Title 1 luôn lớn hơn Body, bất kể cấp độ co giãn. Hệ số co giãn khác nhau: tiêu đề co giãn mạnh hơn văn bản chính, để phân cấp được duy trì ngay cả ở các cấp độ tiếp cận.
iOS hỗ trợ 11 cấp độ co giãn văn bản, được chia thành hai loại:
Sự khác biệt giữa XS và AccessibilityXXXL cho kiểu body dao động từ 14px đến 53px — gần 4 lần. Bố cục được thiết kế cho 17px sẽ hoàn toàn hỏng ở 53px: văn bản tràn ra ngoài, các nút chồng lên nhau, các ô va chạm nhau.
Kiểm tra loại hiện tại trong mã:
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
// Bật bố cục thay thế
}
Loại kích thước văn bản có sẵn thông qua traitCollection.uiContentSizeCategory. Khi cài đặt hệ thống thay đổi, iOS gọi traitCollectionDidChange trên tất cả UIView. Trong phương thức này, bạn cần cập nhật phông chữ và tính toán lại bố cục. SwiftUI thực hiện điều này tự động — UIKit yêu cầu đăng ký thủ công.
Đối với UICollectionView, hãy sử dụng UICollectionViewCompositionalLayout — nó tự động điều chỉnh số cột theo chiều rộng màn hình và kích thước văn bản. Ở các cấp độ tiếp cận, hãy chuyển từ bố cục hai cột sang một cột để văn bản không bị cắt và các phần tử không chồng lên nhau. Sử dụng bố cục có điều kiện: với chiều rộng thông thường — hai cột, với compact hoặc tiếp cận — một cột.
Triển khai cơ bản trong UIKit — UIFont.preferredFont(forTextStyle:). Phương thức này trả về phông chữ được co giãn theo cài đặt hệ thống hiện tại:
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)
Đối với phông chữ tùy chỉnh, hãy sử dụng UIFontMetrics:
let customFont = UIFont(name: "Montserrat-Regular", size: 16)!
titleLabel.font = UIFontMetrics(forTextStyle: .body)
.scaledFont(for: customFont)
// Theo dõi thay đổi kích thước
NotificationCenter.default.addObserver(
self,
selector: #selector(preferredContentSizeChanged),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
Đối với UILabel trong Interface Builder, chỉ cần đặt phông chữ làm kiểu văn bản và bật “Automatically Adjusts Font”. Đối với phông chữ tùy chỉnh, Interface Builder không hỗ trợ UIFontMetrics — chỉ thông qua mã.
UIFontMetrics sử dụng cùng đường cong co giãn như preferredFont. Bạn có thể chỉ định fromTextStyle: .body, .headline, v.v. Mỗi kiểu có hệ số co giãn riêng. Body co giãn vừa phải, Large Title co giãn mạnh. Nếu phông chữ tùy chỉnh của bạn được sử dụng cho văn bản chính, hãy sử dụng .body.
Trong SwiftUI, hỗ trợ Dynamic Type được tích hợp sẵn theo mặc định. Tất cả các bộ sửa đổi hệ thống (.font(.body), .font(.title)) đều tự động co giãn. Nhà phát triển không cần gọi UIFont.preferredFont.
Ví dụ:
Text("Văn bản chính")
.font(.body)
.lineLimit(nil)
.minimumScaleFactor(0.5)
Đối với tỉ lệ tùy chỉnh, hãy sử dụng DynamicTypeSize:
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
Text("Văn bản thích ứng")
.font(.body)
.padding(dynamicTypeSize <= .large ? 8 : 16)
}
SwiftUI tự động cập nhật chế độ xem khi kích thước văn bản hệ thống thay đổi — không cần đăng ký thông báo bổ sung.
Bộ sửa đổi .font(.body) chỉ hoạt động với phông chữ hệ thống. Đối với phông chữ tùy chỉnh trong SwiftUI, hãy sử dụng Font.custom với UIFontMetrics ở bên trong. Bắt đầu từ iOS 16, SwiftUI hỗ trợ DynamicTypeSize trong @Environment, cho phép thích ứng khoảng đệm và bố cục.
Auto Layout là điều kiện tiên quyết để hỗ trợ Dynamic Type. Chiều rộng và chiều cao cố định (>=, <=) bị hỏng ở các kích thước tiếp cận. Sử dụng intrinsicContentSize cho UILabel — nó tự động tính chiều cao cho kích thước phông chữ hiện tại.
Quy tắc bố cục thích ứng:
Đối với văn bản dài (ví dụ: bài viết, điều khoản sử dụng), hãy đặt minimumScaleFactor trên UILabel — điều này thu nhỏ văn bản như biện pháp cuối cùng khi Auto Layout không thể chứa nội dung. Giá trị 0.5 có nghĩa là phông chữ có thể thu nhỏ tới 50% kích thước ưa thích.
Ví dụ về điều chỉnh khoảng đệm theo loại kích thước:
let isAccessibility = traitCollection
.preferredContentSizeCategory.isAccessibilityCategory
stackView.spacing = isAccessibility ? 16 : 8
button.contentEdgeInsets = isAccessibility
? UIEdgeInsets(top: 16, left: 24, bottom: 16, right: 24)
: UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
Văn bản bị cắt — UILabel với numberOfLines = 1 và chiều rộng cố định cắt văn bản ở AccessibilityXL. Giải pháp: numberOfLines = 0 và ràng buộc trailing. Các phần tử chồng lên nhau — các nút có chiều cao cố định chồng lên nhau. Giải pháp: UIStackView với khoảng cách tự động. Nội dung ra ngoài màn hình — ScrollView là bắt buộc đối với các cấp độ tiếp cận.
Trình mô phỏng Xcode cho phép thay đổi kích thước văn bản: trong menu trình mô phỏng, vào Settings → Accessibility → Display & Text Size → Larger Text. Chuyển đổi giữa tất cả 11 cấp độ và xác minh rằng văn bản không bị cắt, các nút có thể truy cập được và bố cục không bị hỏng.
Đối với kiểm tra tự động, hãy sử dụng cài đặt contentSizeCategory trong XCUIApplication:
func testAccessibilitySizes() {
let app = XCUIApplication()
app.launchArguments += [
"-UIPreferredContentSizeCategoryName",
"UICTContentSizeCategoryAccessibilityXXXL"
]
app.launch()
app.scrollViews.buttons["Gửi"].tap()
XCTAssertTrue(app.staticTexts["Đã gửi biểu mẫu"]
.waitForExistence(timeout: 5))
}
XCUITest với các launchArguments khác nhau cho phép kiểm tra tất cả các cấp độ co giãn trong CI. Đừng quên kiểm tra riêng các loại tiếp cận — chúng thường làm hỏng bố cục nhất. Theo Apple, 70% lỗi Dynamic Type được tìm thấy ở các cấp độ tiếp cận, vì các nhà phát triển chỉ kiểm tra kích thước tiêu chuẩn.
Xcode Accessibility Inspector hiển thị phông chữ mà phần tử được chọn sử dụng — cố định hoặc có thể co giãn. Nếu phần tử không phản ứng với thay đổi kích thước văn bản trong trình mô phỏng, thì phông chữ cố định đang được sử dụng. Hãy thay thế nó bằng UIFont.preferredFont hoặc UIFontMetrics.
Câu hỏi thường gặp
Đó là tự động co giãn văn bản trong ứng dụng theo cài đặt kích thước hệ thống. Người dùng thay đổi kích thước trong Cài đặt — tất cả ứng dụng được hỗ trợ sẽ thích ứng mà không cần sự can thiệp của nhà phát triển.
Không. Đối với phông chữ tùy chỉnh, hãy sử dụng UIFontMetrics(scaledFont:). Phương thức này co giãn bất kỳ phông chữ nào so với kiểu văn bản được chỉ định, giữ nguyên tỷ lệ.
11 cấp độ: 5 tiêu chuẩn (XS, S, M, L, XL) và 6 cấp độ tiếp cận (từ AccessibilityXL đến AccessibilityXXXXXL). Kích thước phông chữ body có thể dao động từ 14px đến 53px.
Trong UIKit thông qua UIContentSizeCategory.didChangeNotification. Trong SwiftUI, sử dụng @Environment(\.dynamicTypeSize) — chế độ xem sẽ tự động cập nhật khi cài đặt hệ thống thay đổi.
Người dùng có cỡ chữ lớn sẽ thấy văn bản bị cắt, các phần tử chồng lên nhau và các nút bị hỏng. Ứng dụng có thể bị từ chối trong quá trình xem xét App Store vì vi phạm yêu cầu về khả năng tiếp cận.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm