Dynamic Type: المفاهيم الأساسية، أنماط النص وكيف يعمل في iOS

المؤلف: IT Sectr نُشر: 2026-05-16 وقت القراءة: 9 دق

Dynamic Type هي ميزة مدمجة في iOS تقوم تلقائياً بتغيير حجم الخط في التطبيق وفقاً لإعدادات النظام الخاصة بالمستخدم. يحدد المستخدم حجم النص المفضل لديه في الإعدادات → الشاشة والسطوع → حجم النص، وتتكيف جميع التطبيقات التي تدعم Dynamic Type دون أي إجراءات إضافية. وفقاً لـ إرشادات واجهة المستخدم من Apple، 2024، فإن دعم Dynamic Type هو متطلب إلزامي للنشر في App Store، لأنه عنصر أساسي من إمكانية الوصول على منصة iOS.

الملخص

  • Dynamic Type — آلية في iOS لتدرج النص تلقائياً وفقاً لإعدادات حجم خط النظام
  • يتم توفير الدعم من خلال أنماط النص (UIFont.TextStyle) — body، headline، caption، title وغيرها
  • يدعم النظام 11 مستوى من التدرج من XSmall إلى AccessibilityXXXL
  • للخطوط المخصصة، يتم استخدام طريقة UIFontMetrics، التي تقوم بتدرج أي خط بالنسبة لنمط body
  • يجب أن يكون التخطيط متكيفاً — UIStackView، Auto Layout والارتفاعات الديناميكية للخلايا إلزامية

ما هو Dynamic Type في 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

ظهر Dynamic Type في iOS 7 مع التصميم المسطح. أضاف iOS 10 دعم الخطوط المخصصة عبر UIFontMetrics. قدم iOS 11 مستويات إمكانية الوصول (حتى AccessibilityXXXL). أضاف iOS 15 Dynamic Type في SwiftUI مع دعم تلقائي. مع كل إصدار، تشدد Apple المتطلبات: بدءاً من iOS 17، تتلقى التطبيقات بدون دعم Dynamic Type تحذيراً عند التحميل إلى App Store Connect.

أنماط النص UIFont.TextStyle

يوفر iOS 8 أنماط نص، لكل منها حجم ووزن محددان مسبقاً للإعداد الافتراضي:

النمطالثابتالحجم (L)الغرض
Large Title.largeTitle34pxالعنوان الرئيسي للشاشة
Title 1.title128pxعنوان القسم
Title 2.title222pxالعنوان الفرعي
Title 3.title320pxعنوان البطاقة
Headline.headline17px (عريض)عريض للتأكيد
Body.body17pxالنص الرئيسي
Callout.callout16pxنص تكميلي
Caption 1.caption112pxتعليق أسفل الصورة
Caption 2.caption211pxتعليق صغير
Footnote.footnote13pxحاشية، ملاحظة

استخدام النمط الصحيح ليس مجرد «مظهر خارجي». UIFont.TextStyle.body في وضع AccessibilityXXXL يمكن أن يصل إلى 53px. إذا كان التطبيق يستخدم خطاً ثابتاً 17px للنص الرئيسي، سيصبح النص غير قابل للقراءة للمستخدمين الذين زادوا حجم الخط.

التسلسل الهرمي البصري من خلال الأنماط

Dynamic Type لا يقوم فقط بالتدرج — بل يحافظ على التسلسل الهرمي البصري. Large Title دائماً أكبر من Title 1، والذي هو أكبر من Body، بغض النظر عن مستوى التدرج. تختلف معاملات التدرج: العناوين تتدرج بشكل أكثر نشاطاً من النص الرئيسي، بحيث يبقى التسلسل الهرمي محفوظاً حتى في مستويات إمكانية الوصول.

مستويات التدرج

يدعم iOS 11 مستوى من تدرج النص، مقسمة إلى فئتين:

  • الأحجام القياسية (5 مستويات): XS، S، M، L (افتراضي)، XL
  • أحجام إمكانية الوصول (6 مستويات): accessibilityXL، accessibilityXXL، accessibilityXXXL، accessibilityXXXXL، accessibilityXXXXXL، accessibilityXXXXXXL

الفرق بين XS وAccessibilityXXXL لنمط body يتراوح من 14px إلى 53px — حوالي 4×. التخطيط المصمم لـ 17px ينكسر تماماً عند 53px: النص يفيض، الأزرار تتداخل، الخلايا تصطدم.

التحقق من الفئة الحالية في الكود:

swift
let category = UIApplication.shared.preferredContentSizeCategory
// .extraSmall, .small, .medium, .large, .extraLarge ...
if category.isAccessibilityCategory {
    // تمكين التخطيط البديل
}

traitCollection وحجم النص

فئة حجم النص متاحة من خلال traitCollection.uiContentSizeCategory. عند تغيير إعداد النظام، يستدعي iOS traitCollectionDidChange على جميع UIView. في هذه الطريقة، تحتاج إلى تحديث الخطوط وإعادة حساب التخطيط. SwiftUI يفعل ذلك تلقائياً — UIKit يتطلب اشتراكاً يدوياً.

بالنسبة لـ UICollectionView، استخدم UICollectionViewCompositionalLayout — يضبط تلقائياً عدد الأعمدة حسب عرض الشاشة وحجم النص. في مستويات إمكانية الوصول، انتقل من تخطيط عمودين إلى تخطيط عمود واحد حتى لا يتم قص النص ولا تتداخل العناصر. استخدم تخطيطاً شرطياً: للعرض العادي — عمودين، للمضغوط أو إمكانية الوصول — عمود واحد.

التنفيذ في UIKit

التنفيذ الأساسي في UIKit — UIFont.preferredFont(forTextStyle:). هذه الطريقة ترجع خطاً مدرجاً وفقاً للإعداد الحالي للنظام:

swift
titleLabel.font = UIFont.preferredFont(forTextStyle: .headline)
bodyLabel.font = UIFont.preferredFont(forTextStyle: .body)

بالنسبة للخطوط المخصصة، استخدم UIFontMetrics:

swift
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 ومنحنى التدرج

يستخدم UIFontMetrics نفس منحنى التدرج الذي يستخدمه preferredFont. يمكنك تحديد fromTextStyle: .body، .headline، إلخ. كل نمط له معامل التدرج الخاص به. Body يتدرج بشكل معتدل، Large Title يتدرج بشكل نشط. إذا كان خطك المخصص يستخدم للنص الرئيسي، استخدم .body.

Dynamic Type في SwiftUI

في SwiftUI، دعم Dynamic Type مدمج بشكل افتراضي. جميع معدّلات النظام (.font(.body)، .font(.title)) تتدرج تلقائياً. لا يحتاج المطور إلى استدعاء UIFont.preferredFont.

مثال:

swift
Text("النص الرئيسي")
    .font(.body)
    .lineLimit(nil)
    .minimumScaleFactor(0.5)

بالنسبة للمقاييس المخصصة، استخدم DynamicTypeSize:

swift
@Environment(\.dynamicTypeSize) var dynamicTypeSize

var body: some View {
    Text("نص متكيف")
        .font(.body)
        .padding(dynamicTypeSize <= .large ? 8 : 16)
}

يقوم SwiftUI تلقائياً بتحديث العرض عند تغيير حجم النص في النظام — لا حاجة لاشتراكات إضافية في الإشعارات.

تقييد Dynamic Type في SwiftUI

معدّل .font(.body) يعمل فقط مع خط النظام. للخطوط المخصصة في SwiftUI، استخدم Font.custom مع UIFontMetrics داخلياً. بدءاً من iOS 16، يدعم SwiftUI DynamicTypeSize في @Environment، مما يسمح بتكييف الهوامش والتخطيط.

تكييف التخطيط للخطوط الكبيرة

Auto Layout شرط أساسي لدعم Dynamic Type. العروض والارتفاعات الثابتة (>=, <=) تنكسر في أحجام إمكانية الوصول. استخدم intrinsicContentSize لـ UILabel — يحسب تلقائياً الارتفاع حسب حجم الخط الحالي.

قواعد التخطيط المتكيف:

  • UIStackView مع distribution = fill و spacing >= 8 — ستنتقل العناصر إلى السطر التالي
  • UITableViewCell مع automaticDimension — ارتفاع الخلية يتكيف مع المحتوى
  • numberOfLines = 0 في UILabel — النص لا يُقص بل يلتف
  • الأزرار مع edgeInsets — أضف هوامش في مستويات إمكانية الوصول عبر traitCollection.preferredContentSizeCategory

للنصوص الطويلة (مثل المقالات، شروط الاستخدام)، قم بتعيين minimumScaleFactor في UILabel — هذا يقلل النص كحل أخير عندما لا يستطيع Auto Layout استيعاب المحتوى. القيمة 0.5 تعني أن الخط يمكن أن يصغر إلى 50% من الحجم المفضل.

مثال على تكييف الهوامش حسب فئة الحجم:

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)

مشاكل التخطيط النموذجية في مستويات إمكانية الوصول

قص النص — UILabel مع numberOfLines = 1 وعرض ثابت يقص النص عند AccessibilityXL. الحل: numberOfLines = 0 و constraint trailing. تداخل العناصر — الأزرار ذات الارتفاع الثابت تتداخل فوق بعضها. الحل: UIStackView مع spacing تلقائي. خروج المحتوى عن حدود الشاشة — ScrollView إلزامي لمستويات إمكانية الوصول.

اختبار Dynamic Type

محاكي Xcode يسمح بتغيير حجم النص: في قائمة المحاكي، اذهب إلى Settings → Accessibility → Display & Text Size → Larger Text. تنقل بين جميع المستويات الـ 11 وتأكد من أن النص لا يُقص، والأزرار قابلة للوصول، والتخطيط لا ينكسر.

للاختبار الآلي، استخدم إعداد contentSizeCategory في XCUIApplication:

swift
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 تظهر تحديداً في مستويات إمكانية الوصول، لأن المطورين يختبرون الأحجام القياسية فقط.

Accessibility Inspector: فحص Dynamic Type

يظهر Xcode Accessibility Inspector الخطوط التي يستخدمها العنصر المحدد — ثابتة أو قابلة للتدرج. إذا كان العنصر لا يستجيب لتغيير حجم النص في المحاكي، فهذا يعني أنه يتم استخدام خط ثابت. استبدله بـ UIFont.preferredFont أو UIFontMetrics.

الأسئلة الشائعة

ما هو Dynamic Type في iOS بكلمات بسيطة؟

هو تدرج تلقائي للنص في التطبيق وفقاً لإعدادات حجم النظام. يغير المستخدم الحجم في الإعدادات — جميع التطبيقات المدعومة تتكيف دون تدخل المطور.

هل يعمل Dynamic Type فقط مع خطوط النظام؟

لا. للخطوط المخصصة، استخدم UIFontMetrics(scaledFont:). هذه الطريقة تقوم بتدرج أي خط بالنسبة لنمط النص المحدد، مع الحفاظ على النسب.

كم عدد مستويات التدرج التي يدعمها iOS؟

11 مستوى: 5 قياسية (XS، S، M، L، XL) و 6 مستويات إمكانية وصول (من AccessibilityXL إلى AccessibilityXXXXXL). يمكن أن يتراوح حجم خط body من 14px إلى 53px.

كيف يمكن الاشتراك في تغييرات حجم النص؟

في UIKit عبر UIContentSizeCategory.didChangeNotification. في SwiftUI، استخدم @Environment(\.dynamicTypeSize) — سيتم تحديث العرض تلقائياً عند تغيير إعداد النظام.

ماذا يحدث إذا لم يتم دعم Dynamic Type؟

المستخدمون ذوو الخط الكبير سيرون نصاً مقطوعاً، وعناصر متداخلة، وأزراراً معطلة. قد يتم رفض التطبيق في مراجعة App Store لانتهاك متطلبات إمكانية الوصول.

الخلاصة

  • Dynamic Type — آلية مدمجة في iOS لتدرج النص حسب إعدادات النظام؛ إلزامية لـ App Store
  • استخدم UIFont.preferredFont(forTextStyle:) للخطوط النظامية و UIFontMetrics للخطوط المخصصة
  • يدعم iOS 11 مستوى من التدرج — من XS إلى AccessibilityXXXXXL (14–53px للنص الرئيسي)
  • في SwiftUI، يعمل Dynamic Type تلقائياً عبر .font(.body) و @Environment(\.dynamicTypeSize)
  • يجب أن يكون التخطيط متكيفاً: UIStackView، automaticDimension في الجداول، numberOfLines = 0
  • اختبر جميع المستويات الـ 11، خاصة فئات إمكانية الوصول — 70% من التخطيطات تنكسر عندها
  • الاشتراك في UIContentSizeCategory.didChangeNotification إلزامي لتطبيقات UIKit

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا