Dynamic Type: khái niệm chính, kiểu văn bản và cách hoạt động trong iOS

Tác giả: IT Sectr Đã đăng: 2026-05-16 Thời gian đọc: 9 phút

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 — cơ chế iOS để tự động co giãn văn bản theo cài đặt kích thước phông chữ hệ thống
  • Hỗ trợ được cung cấp thông qua kiểu văn bản (UIFont.TextStyle) — body, headline, caption, title và các kiểu khác
  • Hệ thống hỗ trợ 11 cấp độ co giãn từ XSmall đến AccessibilityXXXL
  • Đối với phông chữ tùy chỉnh, sử dụng phương thức UIFontMetrics, co giãn bất kỳ phông chữ nào so với kiểu body
  • Bố cục phải thích ứng — UIStackView, Auto Layout và chiều cao động của ô là bắt buộc

Dynamic Type trong iOS là gì

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.

Lịch sử phát triển của Dynamic Type

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.

Kiểu văn bản UIFont.TextStyle

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ểuHằng sốKích thước (L)Mục đích
Large Title.largeTitle34pxTiêu đề chính của màn hình
Title 1.title128pxTiêu đề phần
Title 2.title222pxTiêu đề phụ
Title 3.title320pxTiêu đề thẻ
Headline.headline17px (đậm)Chữ đậm để nhấn mạnh
Body.body17pxVăn bản chính
Callout.callout16pxVăn bản bổ trợ
Caption 1.caption112pxChú thích hình ảnh
Caption 2.caption211pxChú thích nhỏ
Footnote.footnote13pxChú 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ữ.

Phân cấp trực quan thông qua kiểu

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.

Cấp độ co giãn

iOS hỗ trợ 11 cấp độ co giãn văn bản, được chia thành hai loại:

  • Kích thước tiêu chuẩn (5 cấp): XS, S, M, L (mặc định), XL
  • Kích thước tiếp cận (6 cấp): accessibilityXL, accessibilityXXL, accessibilityXXXL, accessibilityXXXXL, accessibilityXXXXXL, accessibilityXXXXXXL

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ã:

swift
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
    // Bật bố cục thay thế
}

traitCollection và kích thước văn bản

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 trong UIKit

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:

swift
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:

swift
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 và đường cong co giãn

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.

Dynamic Type trong SwiftUI

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ụ:

swift
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:

swift
@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.

Giới hạn Dynamic Type trong SwiftUI

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.

Thích ứng bố cục cho phông chữ lớn

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:

  • UIStackView với distribution = fill và spacing >= 8 — các phần tử sẽ được chuyển xuống dòng tiếp theo
  • UITableViewCell với automaticDimension — chiều cao ô điều chỉnh theo nội dung
  • numberOfLines = 0 trên UILabel — văn bản không bị cắt mà được xuống dòng
  • Các nút có edgeInsets — thêm khoảng đệm ở các cấp độ tiếp cận thông qua traitCollection.preferredContentSizeCategory

Đố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:

swift
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)

Các vấn đề bố cục điển hình ở cấp độ tiếp cận

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.

Kiểm tra Dynamic Type

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:

swift
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.

Accessibility Inspector: kiểm tra Dynamic Type

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

Dynamic Type trong iOS theo cách đơn giản là gì?

Đó 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.

Dynamic Type chỉ hoạt động với phông chữ hệ thống?

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ệ.

iOS hỗ trợ bao nhiêu cấp độ co giãn?

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.

Làm thế nào để đăng ký thay đổi kích thước văn bản?

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.

Điều gì xảy ra nếu không hỗ trợ Dynamic Type?

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

  • Dynamic Type — cơ chế tích hợp sẵn trong iOS để co giãn văn bản theo cài đặt hệ thống; bắt buộc đối với App Store
  • Sử dụng UIFont.preferredFont(forTextStyle:) cho phông chữ hệ thống và UIFontMetrics cho phông chữ tùy chỉnh
  • iOS hỗ trợ 11 cấp độ co giãn — từ XS đến AccessibilityXXXXXL (14–53px cho body)
  • Trong SwiftUI, Dynamic Type hoạt động tự động thông qua .font(.body) và @Environment(\.dynamicTypeSize)
  • Bố cục phải thích ứng: UIStackView, automaticDimension trong bảng, numberOfLines = 0
  • Kiểm tra tất cả 11 cấp độ, đặc biệt là các loại tiếp cận — 70% bố cục hỏng ở các cấp này
  • Đăng ký UIContentSizeCategory.didChangeNotification là bắt buộc đối với ứng dụng UIKit

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.

Thảo luận dự án

Đọc thêm