Dynamic Type — یک قابلیت داخلی iOS است که بهطور خودکار اندازه فونت را در برنامه مطابق تنظیمات سیستم کاربر تغییر میدهد. کاربر اندازه متن مورد نظر خود را در تنظیمات → صفحه و روشنایی → اندازه متن تعیین میکند، و همه برنامههایی که 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»، بیش از 40% از کاربران iOS اندازه فونت را از حالت پیشفرض تغییر میدهند. برای گروه سنی 65+، این شاخص به 70% میرسد. Dynamic Type یک الزام گواهی دسترسپذیری App Store است. نبود پشتیبانی دلیل رد برنامه در بررسی است.
اصل کار: برنامه به جای UIFont(name:size:) از UIFont.preferredFont(forTextStyle:) استفاده میکند. 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 (bold) | ضخیم برای تاکید |
| 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 بزرگتر است، که آن هم از 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 روی همه UIViewها traitCollectionDidChange را فراخوان میکند. در این روش باید فونتها را بهروز کرده و چیدمان را مجدداً محاسبه کرد. 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» را فعال کنید. برای فونتهای سفارشی، IB از 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 است. عرضها و ارتفاعهای ثابت (>=, <=) در اندازههای دسترسپذیری مخروب میشوند. برای UILabel از intrinsicContentSize استفاده کنید — آن ارتفاع را بر اساس اندازه فونت جاری بهطور خودکار محاسبه میکند.
قوانین چیدمان سازگارشو:
برای متون طولانی (مانند مقالات، شرایط استفاده) روی UILabel minimumScaleFactor را تنظیم کنید — این متن را به عنوان آخرین چاره کوچک میکند زمانی که 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 constraint. تداخل عناصر — دکمههایی با ارتفاع ثابت بر یکدیگر میافتند. راهحل: UIStackView با automatic 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 از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید