ประเด็นสำคัญ
Dynamic Type คือเทคโนโลยีของ Apple ที่ช่วยให้ฟอนต์ของแอปปรับขนาดโดยอัตโนมัติเมื่อขนาดข้อความของระบบเปลี่ยนแปลง ผู้ใช้กำหนดขนาดที่ต้องการในการตั้งค่า → การช่วยเหลือการเข้าถึง → จอภาพและขนาดข้อความ และแอปทั้งหมดที่รองรับ Dynamic Type จะปรับขนาดฟอนต์โดยไม่ต้องรีสตาร์ท
ระบบมีระดับการปรับขนาด 11 ระดับ: จาก XS (14pt พื้นฐาน) ถึง XXXL (23pt พื้นฐาน) พร้อมขนาดการช่วยเหลือการเข้าถึงเพิ่มเติมอีก 5 ขนาด (AX1–AX5) สำหรับผู้ใช้ที่มีความบกพร่องทางการมองเห็นอย่างรุนแรง เมื่อขนาดเปลี่ยนแปลง iOS จะสร้างการแจ้งเตือน UIContentSizeCategory.didChangeNotification และแอปต้องโหลดฟอนต์ใหม่ผ่าน UIFontMetrics ตาม Apple Human Interface Guidelines Dynamic Type ไม่เปลี่ยนระยะห่างระหว่างบรรทัดหรือสัดส่วนตัวอักษร — เฉพาะขนาดฟอนต์เท่านั้น ซึ่งคงความสามารถในการอ่านในทุกขนาด
Dynamic Type จำเป็นสำหรับแอปที่ต้องการสถานะการช่วยเหลือการเข้าถึง ที่ WWDC 2024 Apple ประกาศว่าแอปที่ไม่รองรับไดนามิกไทป์เสี่ยงถูกปฏิเสธระหว่างการตรวจสอบหากฟังก์ชันหลักเกี่ยวข้องกับการอ่านข้อความ ในโครงการของ IT Sectr เรานำ Dynamic Type มาใช้ตั้งแต่เวอร์ชันแรก — ซึ่งประหยัดเวลาได้ถึง 20% ในการปรับการช่วยเหลือการเข้าถึงในภายหลัง
Apple มีรูปแบบข้อความที่กำหนดไว้ล่วงหน้า 11 รูปแบบ แต่ละรูปแบบแสดงผ่าน UIFontDescriptor.UIAttributes สำหรับฟอนต์ระบบ SF Pro นักพัฒนาไม่ได้ระบุขนาดเป็นพิกเซล — เขาเลือกรูปแบบเชิงความหมาย และ iOS ใช้ขนาดฟอนต์จริงตามการตั้งค่าของผู้ใช้
| รูปแบบ | ขนาด (ค่าเริ่มต้น) | ขนาด (AX5) | การใช้งาน |
|---|---|---|---|
| .largeTitle | 34pt | 62pt | ชื่อเรื่องหน้าจอระดับแรก |
| .title1 | 28pt | 50pt | หัวเรื่องรอง |
| .title2 | 22pt | 40pt | หัวเรื่องส่วน |
| .title3 | 20pt | 36pt | หัวเรื่องย่อย |
| .headline | 17pt semibold | 31pt | ข้อความเน้นในรายการ |
| .body | 17pt | 31pt | เนื้อหาหลัก |
| .callout | 16pt | 29pt | ข้อความเสริมและคำอธิบายเพิ่มเติม |
| .subheadline | 15pt | 27pt | ป้ายกำกับองค์ประกอบ |
| .footnote | 13pt | 23pt | เชิงอรรถและข้อความขนาดเล็ก |
| .caption1 | 12pt | 21pt | คำอธิบายภาพ |
| .caption2 | 11pt | 19pt | ป้ายกำกับและคำอธิบายภาพขนาดเล็ก |
แต่ละรูปแบบใช้ฟอนต์ระบบ SF Pro ที่มีความหนาคงที่ (Regular สำหรับ body, Bold สำหรับ headline) ฟอนต์ที่กำหนดเองเชื่อมต่อผ่าน UIFontMetrics — วิธีที่ถูกต้องเพียงวิธีเดียวในการปรับฟอนต์ของบุคคลที่สามให้เข้ากับไดนามิกไทป์
UIFontMetrics เป็นคลาสที่เปิดตัวใน iOS 11 ซึ่งปรับขนาด UIFont ใดๆ ตามสัดส่วนของรูปแบบข้อความที่เลือก ก่อน iOS 11 นักพัฒนาใช้การเรียก preferredFontForTextStyle โดยตรง ซึ่งคืนค่าเฉพาะฟอนต์ระบบ SF Pro เท่านั้น UIFontMetrics แก้ปัญหานี้: มันรับฟอนต์ใดๆ และคืนเวอร์ชันที่ปรับขนาดแล้ว โดยคงความหนาและสัดส่วนไว้
เมธอด scaledFont(for:) คำนวณปัจจัยการปรับขนาดตามขนาดข้อความปัจจุบันของผู้ใช้: หากเลือกใหญ่ ปัจจัยคือ 1.0 หากใหญ่มาก (AX1) — ประมาณ 1.3 สำหรับสูงสุด (AX5) — สูงถึง 1.8 ปัจจัยจะถูกนำไปใช้กับขนาดฐานของฟอนต์ที่กำหนดเอง ไม่ใช่ฟอนต์ระบบ — ซึ่งรับประกันว่าความตั้งใจของนักออกแบบจะคงอยู่ในทุกขนาด
UIFontMetrics แนะนำให้ใช้กับฟอนต์ที่กำหนดเองทั้งหมดในแอป ที่ WWDC 2024 Apple แสดงเครื่องมือ Accessibility Inspector ซึ่งตรวจสอบการรองรับ Dynamic Type และเน้นองค์ประกอบที่ใช้ขนาดฟอนต์คงที่แทน UIFontMetrics ที่ IT Sectr เราใช้งาน UIFontMetrics ในทุกโครงการตั้งแต่ปี 2018 — ซึ่งลดบักการทับซ้อนของข้อความลง 35%
วิธีที่ง่ายที่สุดในการรับฟอนต์ไดนามิกสำหรับป้ายกำกับ โค้ดแสดงวิธีการตั้งค่า UILabel ด้วยรูปแบบ .body ที่ตอบสนองต่อการเปลี่ยนแปลงขนาดข้อความของระบบโดยอัตโนมัติ
import UIKit
class GreetingViewController: UIViewController {
private let label: UILabel = {
let l = UILabel()
l.text = "Hello, Dynamic Type!"
l.font = UIFont.preferredFont(forTextStyle: .body)
l.adjustsFontForContentSizeCategory = true
l.translatesAutoresizingMaskIntoConstraints = false
return l
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
}
แฟล็ก adjustsFontForContentSizeCategory = true อัปเดตฟอนต์โดยอัตโนมัติเมื่อขนาดข้อความของระบบเปลี่ยนแปลง — หากไม่มีแฟล็กนี้ Dynamic Type จะไม่ทำงานสำหรับป้ายกำกับที่มีอยู่ เมื่อขนาดเปลี่ยนแปลง iOS จะเรียก layoutIfNeeded และป้ายกำกับอัปเดตฟอนต์โดยไม่ต้องดำเนินการด้วยตนเอง
เมื่อใช้ฟอนต์ที่กำหนดเอง (เช่น Montserrat) การเรียก preferredFontForTextStyle จะคืนค่า SF Pro ไม่ใช่ฟอนต์ของคุณ UIFontMetrics จะปรับขนาดฟอนต์ที่กำหนดเองโดยเฉพาะ โดยคงการออกแบบไว้
import UIKit
extension UIFont {
static func customDynamicFont(name: String,
size: CGFloat,
style: UIFont.TextStyle) -> UIFont {
guard let baseFont = UIFont(name: name, size: size) else {
return .preferredFont(forTextStyle: style)
}
return UIFontMetrics(forTextStyle: style).scaledFont(for: baseFont)
}
}
let titleFont = UIFont.customDynamicFont(
name: "Montserrat-Bold",
size: 20,
style: .title3
)
เมธอด scaledFont(for:) รับ UIFont พื้นฐานและคืนเวอร์ชันที่ปรับขนาดตามสัดส่วนของรูปแบบ .title3 ที่ขนาดการช่วยเหลือการเข้าถึง AX5 ฟอนต์ Montserrat-Bold 20pt จะกลายเป็น ~36pt — เท่ากับที่ฟอนต์ระบบของรูปแบบนี้จะเพิ่มขึ้น ที่ IT Sectr เราใช้รูปแบบนี้ในทุกโครงการที่มีฟอนต์ที่กำหนดเองตั้งแต่ปี 2018 ซึ่งช่วยขจัดการร้องเรียนเกี่ยวกับข้อความขนาดเล็กจากผู้ใช้ที่มีความบกพร่องทางการมองเห็นได้อย่างสมบูรณ์
หากคุณอัปเดตฟอนต์ด้วยตนเอง (โดยไม่มี adjustsFontForContentSizeCategory) ให้สมัครรับการแจ้งเตือน UIContentSizeCategory.didChangeNotification ซึ่งจำเป็นสำหรับองค์ประกอบ UI ที่กำหนดเองที่ไม่ได้รับการอัปเดตฟอนต์อัตโนมัติ
import UIKit
class DynamicLabel: UILabel {
private var customFont: UIFont?
private var textStyle: UIFont.TextStyle = .body
func configure(font: UIFont, style: UIFont.TextStyle) {
customFont = font
textStyle = style
NotificationCenter.default.addObserver(
self,
selector: #selector(updateFont),
name: UIContentSizeCategory.didChangeNotification,
object: nil
)
updateFont()
}
@objc private func updateFont() {
guard let base = customFont else { return }
self.font = UIFontMetrics(forTextStyle: textStyle).scaledFont(for: base)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
การสมัครรับ didChangeNotification รับประกันว่าองค์ประกอบที่กำหนดเองจะอัปเดตฟอนต์ทุกครั้งที่การตั้งค่าระบบเปลี่ยนโดยไม่ต้องรีสตาร์ทแอป ตั้งแต่ iOS 15 การแจ้งเตือนจะมาแม้เมื่อขนาดข้อความถูกเปลี่ยนผ่านศูนย์ควบคุมในแอปที่รองรับ Live Text Size
คำถามที่พบบ่อย
Dynamic Type ใช้งานได้บน iOS 7 ขึ้นไป UIFontMetrics ปรากฏใน iOS 11 — ก่อนหน้านั้นใช้เมธอด preferredFontForTextStyle โดยตรง บน iOS 15+ ไดนามิกไทป์รองรับขนาดการช่วยเหลือการเข้าถึงเพิ่มเติม (AX1–AX5) สำหรับฟอนต์ขนาดใหญ่ แอปที่รองรับ iOS 10 และต่ำกว่าใช้ preferredFontForTextStyle โดยไม่มี UIFontMetrics ซึ่งจำกัดการรองรับเฉพาะฟอนต์ระบบ SF Pro เท่านั้น
ใน Xcode 15+ เปิดเครื่องจำลองแล้วไปที่การตั้งค่า → การช่วยเหลือการเข้าถึง → จอภาพและขนาดข้อความ → ข้อความขนาดใหญ่ ลากแถบเลื่อนเพื่อเปลี่ยนขนาด ใน Xcode มี Debug → Accessibility Inspector ซึ่งเน้นองค์ประกอบที่มีฟอนต์คงที่ สำหรับระบบอัตโนมัติ ให้ใช้การทดสอบที่เปลี่ยน UISlider การตั้งค่าผ่าน XCUITest — ซึ่งรับประกันว่าหน้าจอทั้งหมดจะสร้างใหม่ได้อย่างถูกต้อง
ใช่ Auto Layout กับไดนามิกไทป์ต้องการการใช้ intrinsicContentSize บน UILabel และ UIButton ที่ขนาดการช่วยเหลือการเข้าถึง ข้อความอาจล้นเกินขอบเขตของ superview — เพิ่ม UIScrollView หรือเพิ่มข้อจำกัด leading/trailing ใช้ UIFontMetrics.scaledValue สำหรับระยะห่าง เพื่อให้ระยะห่างระหว่างตัวอักษรปรับขนาดตามสัดส่วนของฟอนต์ด้วย
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ