Dynamic Type هي ميزة مدمجة في iOS تقوم تلقائياً بتغيير حجم الخط في التطبيق وفقاً لإعدادات النظام الخاصة بالمستخدم. يحدد المستخدم حجم النص المفضل لديه في الإعدادات → الشاشة والسطوع → حجم النص، وتتكيف جميع التطبيقات التي تدعم Dynamic Type دون أي إجراءات إضافية. وفقاً لـ إرشادات واجهة المستخدم من Apple، 2024، فإن دعم Dynamic Type هو متطلب إلزامي للنشر في App Store، لأنه عنصر أساسي من إمكانية الوصول على منصة iOS.
الملخص
Dynamic Type هي تقنية iOS ظهرت في iOS 7 وتسمح للنص في التطبيق بالتكيف تلقائياً مع إعدادات حجم خط النظام. يمكن للمستخدم زيادة أو تقليل الخط في جميع التطبيقات دفعة واحدة — دون الحاجة إلى تغيير الإعدادات داخل كل تطبيق على حدة.
وفقاً لـ Apple WWDC 2023، «Make Your App Visually Accessible»، أكثر من 40% من مستخدمي iOS يغيرون حجم الخط من الإعداد الافتراضي. بالنسبة للفئة العمرية 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 للنص الرئيسي، سيصبح النص غير قابل للقراءة للمستخدمين الذين زادوا حجم الخط.
Dynamic Type لا يقوم فقط بالتدرج — بل يحافظ على التسلسل الهرمي البصري. Large Title دائماً أكبر من 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 — يضبط تلقائياً عدد الأعمدة حسب عرض الشاشة وحجم النص. في مستويات إمكانية الوصول، انتقل من تخطيط عمودين إلى تخطيط عمود واحد حتى لا يتم قص النص ولا تتداخل العناصر. استخدم تخطيطاً شرطياً: للعرض العادي — عمودين، للمضغوط أو إمكانية الوصول — عمود واحد.
التنفيذ الأساسي في 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، يكفي تعيين الخط كنمط نص وتفعيل «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 و constraint trailing. تداخل العناصر — الأزرار ذات الارتفاع الثابت تتداخل فوق بعضها. الحل: UIStackView مع spacing تلقائي. خروج المحتوى عن حدود الشاشة — ScrollView إلزامي لمستويات إمكانية الوصول.
محاكي Xcode يسمح بتغيير حجم النص: في قائمة المحاكي، اذهب إلى 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.
الأسئلة الشائعة
هو تدرج تلقائي للنص في التطبيق وفقاً لإعدادات حجم النظام. يغير المستخدم الحجم في الإعدادات — جميع التطبيقات المدعومة تتكيف دون تدخل المطور.
لا. للخطوط المخصصة، استخدم UIFontMetrics(scaledFont:). هذه الطريقة تقوم بتدرج أي خط بالنسبة لنمط النص المحدد، مع الحفاظ على النسب.
11 مستوى: 5 قياسية (XS، S، M، L، XL) و 6 مستويات إمكانية وصول (من AccessibilityXL إلى AccessibilityXXXXXL). يمكن أن يتراوح حجم خط body من 14px إلى 53px.
في UIKit عبر UIContentSizeCategory.didChangeNotification. في SwiftUI، استخدم @Environment(\.dynamicTypeSize) — سيتم تحديث العرض تلقائياً عند تغيير إعداد النظام.
المستخدمون ذوو الخط الكبير سيرون نصاً مقطوعاً، وعناصر متداخلة، وأزراراً معطلة. قد يتم رفض التطبيق في مراجعة App Store لانتهاك متطلبات إمكانية الوصول.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا