Dynamic Type เป็นฟีเจอร์ที่ติดตั้งมาใน iOS ที่เปลี่ยนขนาดแบบอักษรในแอปโดยอัตโนมัติตามการตั้งค่าระบบของผู้ใช้ ผู้ใช้กำหนดขนาดข้อความที่ต้องการใน Settings → Display & Brightness → Text Size และแอปทั้งหมดที่รองรับ Dynamic Type จะปรับตัวโดยไม่ต้องมีการกระทำเพิ่มเติม ตาม Apple Human Interface Guidelines, 2024 การรองรับ Dynamic Type เป็นข้อกำหนดที่จำเป็นสำหรับการเผยแพร่ใน App Store เนื่องจากเป็น องค์ประกอบพื้นฐาน ของการเข้าถึงได้บนแพลตฟอร์ม iOS
สาระสำคัญ
Dynamic Type เป็นเทคโนโลยีของ iOS ที่เปิดตัวใน iOS 7 ซึ่งทำให้ข้อความในแอปปรับตัวไปยังการตั้งค่าขนาดแบบอักษรของระบบโดยอัตโนมัติ ผู้ใช้สามารถเพิ่มหรือลดแบบอักษรในทุกแอพพร้อมกันได้ — โดยไม่ต้องเปลี่ยนการตั้งค่าภายในแต่ละแอพพ์แยกกัน
ตาม Apple WWDC 2023, “Make Your App Visually Accessible” ผู้ใช้ iOS มากกว่า 40% เปลี่ยนขนาดแบบอักษรจากค่าเริ่มต้น สำหรับกลุ่มอายุ 65+ ตัวเลขนี้สูงถึง 70% Dynamic Type เป็นข้อกำหนดที่จำเป็นสำหรับการรับรองการเข้าถึงได้ของ App Store การขาดการรองรับเป็นสาเหตุในการปฏิเสธแอพระหว่างการตรวจสอบ
หลักการทำงาน: แอพใช้ UIFont.preferredFont(forTextStyle:) แทน UIFont(name:size:) iOS จะส่งคืนแบบอักษรที่ปรับขนาดแล้วตามการตั้งค่าระบบปัจจุบันโดยอัตโนมัติ เมื่อขนาดเปลี่ยนไปในการตั้งค่า iOS จะสร้าง UIContentSizeCategory.didChangeNotification — แอพต้องคำนวณเลย์เอาต์ใหม่
Dynamic Type เปิดตัวใน iOS 7 พร้อมกับดีไซน์เรียบ iOS 10 เพิ่มการรองรับแบบอักษรที่กำหนดเองผ่าน UIFontMetrics iOS 11 แนะนำระดับการเข้าถึงได้ (ถึง AccessibilityXXXL) iOS 15 เพิ่ม Dynamic Type ใน SwiftUI ด้วยการรองรับอัตโนมัติ ทุกรุ่นที่เผยแพร่ Apple เพิ่มความเข้มงวด: ตั้งแต่ iOS 17 เป็นต้นไป แอพที่ไม่มีการรองรับ Dynamic Type จะได้รับ คำเตือน เมื่ออัปโหลดไปยัง App Store Connect
iOS มี 8 รูปแบบข้อความ แต่ละแบบมีขนาดและความหนาที่กำหนดไว้ล่วงหน้าสำหรับการตั้งค่าเริ่มต้น:
| รูปแบบ | ค่าคงที่ | ขนาด (L) | วัตถุประสงค์ |
|---|---|---|---|
| Large Title | .largeTitle | 34px | ชื่อเรื่องหลักของหน้าจอ |
| Title 1 | .title1 | 28px | หัวข้อส่วน |
| Title 2 | .title2 | 22px | หัวข้อย่อย |
| Title 3 | .title3 | 20px | ชื่อเรื่องของการ์ด |
| Headline | .headline | 17px (ตัวหนา) | ตัวหนาสำหรับเน้น |
| Body | .body | 17px | ข้อความหลัก |
| Callout | .callout | 16px | ข้อความเสริม |
| Caption 1 | .caption1 | 12px | คำอธิบายภาพ |
| Caption 2 | .caption2 | 11px | คำอธิบายขนาดเล็ก |
| Footnote | .footnote | 13px | เชิงอรรถ, หมายเหตุ |
การใช้รูปแบบที่ถูกต้องไม่ใช่แค่เรื่องของ “รูปลักษณ์ภายนอก” UIFont.TextStyle.body ในโหมด AccessibilityXXXL สามารถสูงถึง 53px หากแอพใช้แบบอักษรตามปกติ 17px สำหรับ body ข้อความจะไม่สามารถอ่านได้สำหรับผู้ใช้ที่เพิ่มขนาดแบบอักษร
Dynamic Type ไม่ได้แค่ปรับขนาด — แต่ยังคงรักษา ลำดับชั้นเส้นทางสายตา Large Title ใหญ่กว่า Title 1 เสมอ และ Title 1 ใหญ่กว่า Body โดยไม่ขึ้นกับระดับการปรับขนาด ค่าสัมประสิทธิ์การปรับขนาดแตกต่างกัน: หัวข้อจะปรับขนาดรุนแรงกว่าข้อความหลัก เพื่อให้ลำดับชั้นยังคงอยู่แม้ในระดับการเข้าถึงได้
iOS รองรับ 11 ระดับ การปรับขนาดข้อความ แบ่งออกเป็นสองหมวดหมู่:
ความแตกต่างระหว่าง XS และ AccessibilityXXXL สำหรับรูปแบบ body อยู่ที่ 14px ถึง 53px — เกือบ 4 เท่า เลย์เอาต์ที่ออกแบบมาสำหรับ 17px จะพังโดยสิ้นเชิ้งที่ 53px: ข้อความล้นเฮือมพันเขต, ปุ่มทับซ้อนกัน, เซลล์ชนกัน
ตรวจสอบหมวดหมู่ปัจจุบันในโค้ด:
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
// เปิดใช้งานเลย์เอาต์ทางเลือก
}
หมวดหมู่ขนาดข้อความสามารถเข้าถึงได้ผ่าน traitCollection.uiContentSizeCategory เมื่อการตั้งค่าระบบเปลี่ยนไป iOS จะเรียก traitCollectionDidChange บน UIView ทั้งหมด ในมีเทอดนี้ คุณต้องอัพเดตแบบอักษรและคำนวณเลย์เอาต์ใหม่ SwiftUI ทำสิ่งนี้โดยอัตโนมัติ — UIKit ต้องการสมัครด้วยตนเอง
สำหรับ UICollectionView ใช้ UICollectionViewCompositionalLayout — จะปรับจำนวนคอลัมน์โดยอัตโนมัติตามความกว้างหน้าจอและขนาดข้อความ ในระดับการเข้าถึงได้ ให้เปลี่ยนจากเลย์เอาต์สองคอลัมน์เป็นเลย์เอาต์คอลัมน์เดียว เพื่อไม่ให้ข้อความถูกตัดและองค์ประกอบไม่ซ้อนกัน ใช้เลย์เอาต์แบบมีเงื่อนไข: สำหรับ regular width — สองคอลัมน์, สำหรับ compact หรือ accessibility — หนึ่งคอลัมน์
การนำไปใช้ขั้นพื้นฐานใน UIKit — UIFont.preferredFont(forTextStyle:) เมทอดนี้จะส่งคืนแบบอักษรที่ปรับขนาดแล้วตามการตั้งค่าระบบปัจจุบัน:
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)
สำหรับ แบบอักษรที่กำหนดเอง ใช้ UIFontMetrics:
let customFont = UIFont(name: "Montserrat-Regular", size: 16)!
titleLabel.font = UIFontMetrics(forTextStyle: .body)
.scaledFont(for: customFont)
// ติดตามการเปลี่ยนแปลงขนาด
NotificationCenter.default.addObserver(
self,
selector: #selector(preferredContentSizeChanged),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
สำหรับ UILabel ใน Interface Builder แค่ตั้งแบบอักษรเป็นรูปแบบข้อความ (Text Style) และเปิดใช้งาน “Automatically Adjusts Font” สำหรับแบบอักษรที่กำหนดเอง Interface Builder ไม่รองรับ UIFontMetrics — ผ่านโค้ดเท่านั้น
UIFontMetrics ใช้เส้นโค้งการปรับขนาดเดียวกับ preferredFont คุณสามารถระบุ fromTextStyle: .body, .headline ได้ แต่ละรูปแบบมีค่าสัมประสิทธิ์การปรับขนาดของตนเอง Body ปรับขนาดปานกลาง, Large Title ปรับขนาดอย่างรุนแรง หากแบบอักษรที่กำหนดเองของคุณถูกใช้สำหรับข้อความหลัก ใช้ .body
ใน SwiftUI การรองรับ Dynamic Type ถูกติดตั้งมาตั้งแต่ต้น ตัวปรับแต่งระบบทั้งหมด (.font(.body), .font(.title)) จะปรับขนาดโดยอัตโนมัติ นักพัฒนาไม่จำเป็นต้องเรียก UIFont.preferredFont
ตัวอย่าง:
Text("ข้อความหลัก")
.font(.body)
.lineLimit(nil)
.minimumScaleFactor(0.5)
สำหรับ การปรับขนาดแบบกำหนดเอง ใช้ DynamicTypeSize:
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var body: some View {
Text("ข้อความแบบปรับตัวได้")
.font(.body)
.padding(dynamicTypeSize <= .large ? 8 : 16)
}
SwiftUI จะอัพเดตมุมมองโดยอัตโนมัติเมื่อขนาดข้อความระบบเปลี่ยนไป — ไม่ต้องมีการสมัครรับข้อความเพิ่มเติม
ตัวปรับแต่ง .font(.body) ทำงานเฉพาะกับแบบอักษรระบบเท่านั้น สำหรับแบบอักษรที่กำหนดเองใน SwiftUI ใช้ Font.custom กับ UIFontMetrics เบื้องหลัง ตั้งแต่ iOS 16 SwiftUI รองรับ DynamicTypeSize ใน @Environment ซึ่งทำให้สามารถปรับรูปแบบรองรับและเลย์เอาต์ได้
Auto Layout เป็นเงื่อนไขที่จำเป็นสำหรับการรองรับ Dynamic Type ความกว้างและความสูงตามเชิง (>=, <=) จะพังในขนาดการเข้าถึงได้ ใช้ intrinsicContentSize สำหรับ UILabel — จะคำนวณความสูงโดยอัตโนมัติสำหรับขนาดแบบอักษรปัจจุบัน
กฎของเลย์เอาต์แบบปรับตัวได้:
สำหรับข้อความยาว (เช่น บทความ, เงื่อนไขการใช้งาน) ให้ตั้ง minimumScaleFactor บน UILabel — นี้จะลดข้อความเป็นตัวเลือกสุดท้ายเมื่อ Auto Layout ไม่สามารถรองรับเนื้อหาได้ ค่า 0.5 หมายความว่าแบบอักษรสามารถลดขนาดได้ถึง 50% ของขนาดที่ต้องการ
ตัวอย่างการปรับรองรับตามหมวดหมู่ขนาด:
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)
การตัดข้อความ — UILabel ด้วย numberOfLines = 1 และความกว้างตามปกติจะตัดข้อความใน AccessibilityXL วิธีแก้: numberOfLines = 0 และข้อจำกัด trailing การซ้อนกันขององค์ประกอบ — ปุ่มที่มีความสูงตามปกติจะซ้อนกัน วิธีแก้: UIStackView ด้วยการวงระยะอัตโนมัติ เนื้อหาออกนอกหน้าจอ — ScrollView เป็นสิ่งจำเป็นสำหรับระดับการเข้าถึงได้
Xcode Simulator ช่วยให้เปลี่ยนขนาดข้อความได้: ในเมนูจำลองไปที่ Settings → Accessibility → Display & Text Size → Larger Text สลับระหว่งทุก 11 ระดับและตรวจสอบว่าข้อความไม่ถูกตัด, ปุ่มสามารถเข้าถึงได้, และเลย์เอาต์ไม่พัง
สำหรับ การทดสอบอัตโนมัติ ใช้การตั้งค่า contentSizeCategory ใน XCUIApplication:
func testAccessibilitySizes() {
let app = XCUIApplication()
app.launchArguments += [
"-UIPreferredContentSizeCategoryName",
"UICTContentSizeCategoryAccessibilityXXXL"
]
app.launch()
app.scrollViews.buttons["ส่ง"].tap()
XCTAssertTrue(app.staticTexts["ส่งแบบฟอร์มแล้ว"]
.waitForExistence(timeout: 5))
}
XCUITest ด้วย launchArguments ที่แตกต่างกันช่วยให้ตรวจสอบทุกระดับการปรับขนาดใน CI อย่าลืมทดสอบหมวดหมู่การเข้าถึงได้แยกต่างหาก — เพราะมักทำให้เลย์เอาต์พัง ตามข้อมูลจาก Apple, 70% ของข้อผิดพลาด Dynamic Type ถูกพบในระดับการเข้าถึงได้ เพราะนักพัฒนามักทดสอบเฉพาะขนาดมาตรฐาน
Xcode Accessibility Inspector แสดงว่าองค์ประกอบที่เลือกใช้แบบอักษรชนิดใด — ตามปกติหรือปรับขนาดได้ หากองค์ประกอบไม่ตอบสนองต่อการเปลี่ยนขนาดข้อความในจำลอง แสดงว่ากำลังใช้แบบอักษรตามปกติ ให้แทนที่ด้วย UIFont.preferredFont หรือ UIFontMetrics
คำถามที่พบบ่อย
มันคือการ ปรับขนาดข้อความโดยอัตโนมัติ ในแอพตามการตั้งค่าขนาดของระบบ ผู้ใช้เปลี่ยนขนาดใน Settings — แอพที่รองรับทั้งหมดจะปรับตัวโดยไม่ต้องให้นักพัฒนาเข้ามาเกี่ยวข้อง
ไม่ สำหรับ แบบอักษรที่กำหนดเอง ใช้ UIFontMetrics(scaledFont:) เมทอดนี้จะปรับขนาดแบบอักษรใดๆเทียบกับรูปแบบข้อความที่ระบุ โดยรักษาสัดส่วนไว้
11 ระดับ: 5 ระดับมาตรฐาน (XS, S, M, L, XL) และ 6 ระดับการเข้าถึงได้ (จาก AccessibilityXL ถึง AccessibilityXXXXXL) ขนาดแบบอักษร body สามารถอยู่ระหว่าง 14px ถึง 53px
ใน UIKit ผ่าน UIContentSizeCategory.didChangeNotification ใน SwiftUI ใช้ @Environment(\.dynamicTypeSize) — มุมมองจะอัพเดตโดยอัตโนมัติเมื่อการตั้งค่าระบบเปลี่ยนไป
ผู้ใช้ที่มีขนาดแบบอักษรใหญ่ขึ้นจะเห็น ข้อความที่ถูกตัด, องค์ประกอบที่ซ้อนกัน และปุ่มที่ใช้งานไม่ได้ แอพอาชugถูกปฏิเสธในการตรวจสอบ App Store เนื่องจากละเมิดข้อกำหนดการเข้าถึงได้
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม