@ScaledMetric — property wrapper SwiftUI na awtomatikong nag-scale ng numerical value ayon sa Dynamic Type setting ng user. Ang value ay binalot sa @ScaledMetric at kinakalkula muli kapag nagbago ang system font size, na ginagarantiyang accessible ang interface para sa mga taong may kapansanan sa paningin. Ayon sa Apple Developer Documentation (2026), ang @ScaledMetric ay gumagamit ng UIFontMetrics scale para kalkulahin ang relative scale batay sa preferred content size category. Magbasa pa tungkol sa accessibility sa materyal tungkol sa accessibility ng SwiftUI.
Mga pangunahing punto
@ScaledMetric — property wrapper SwiftUI, idinagdag sa iOS 14, na awtomatikong nag-scale ng numerical value (CGFloat, Int, Double) sa kasalukuyang Dynamic Type font size. Hindi tulad ng .font(.body) para sa mga font, ang @ScaledMetric ay nag-scale ng anumang numerical parameter: padding, spacing, cornerRadius, iconSize — lahat ng dapat proporsyonal na lumaki kapag malaking text.
Ang pangunahing gawain ng @ScaledMetric ay magbigay ng accessibility-scaling ng non-text interface elements. Kapag pinalaki ng user ang font sa iOS settings, ang mga button, icon at spacing ay dapat proporsyonal na lumaki para manatiling balanse ang interface. Ang @ScaledMetric ay awtomatikong lumulutas sa gawaing ito, nang walang manual na pagkalkula ng multiplier.
Basic na syntax Ang @ScaledMetric ay gumagamit ng default na value at opsyonal na parameter na relativeTo. Kung ang relativeTo ay tinukoy, ang pag-scale ay nakatali sa isang partikular na text style (UIFontTextStyle). Kung hindi — ang .body scale ang ginagamit.
struct AccessibleButton: View {
@ScaledMetric private var padding: CGFloat = 12
@ScaledMetric(relativeTo: .title) private var iconSize: CGFloat = 24
var body: some View {
Label("Isumite", systemImage: "checkmark.circle.fill")
.font(.body)
.padding(padding)
.imageScale(.init(rawValue: iconSize / 24) ?? .medium)
}
}
Ang padding ay i-scale kaugnay ng .body (default), iconSize — kaugnay ng .title. Sa malaking text, proporsyonal na tataas ang spacing at icon. Kung walang @ScaledMetric, mananatiling 12 pt ang spacing sa anumang laki ng font, na magdudulot ng visual imbalance.
Ang mekanismo ng @ScaledMetric ay nakabatay sa UIFontMetrics mula sa UIKit. Kapag gumawa ang SwiftUI ng @ScaledMetric instance, kinakalkula nito ang multiplier batay sa kasalukuyang preferred content size category (UIContentSizeCategory). Ang base value ay pinaparami ng scaledValue mula sa UIFontMetrics para sa tinukoy na text style.
Sa matematika: ScaledMetricValue = baseValue × UIFontMetrics.scaledValue(for: relativeTo). Kung hindi tinukoy ang relativeTo, ginagamit ang UIFontMetrics.default na nakatali sa .body. Kapag nagbago ang Dynamic Type, muling ginagawa ng SwiftUI ang body ng View, kinakalkula ng @ScaledMetric ang bagong scaledValue at awtomatikong nag-a-update ang UI sa pamamagitan ng mekanismo ng @State-like na PropertyWrappers.
Ang iOS scale ay may kasamang 11 laki: mula .extraSmall (5 pt) hanggang .accessibilityExtraExtraExtraLarge (77 pt para sa .body). Ang scaling coefficient para sa .body ay nag-iiba mula 0.85 (XS) hanggang 1.71 (XXXL) kaugnay ng base value. Ginagamit ng @ScaledMetric ang eksaktong scale na ito, kaya ang value na 12 pt para sa padding ay maaaring maging ~20 pt sa maximum na accessibility size.
| Content Size Category | Coefficient (body) | Halimbawa @ScaledMetric(12) |
|---|---|---|
| extraSmall | 0.85 | ~10 pt |
| small | 0.93 | ~11 pt |
| medium (default) | 1.00 | 12 pt |
| large | 1.07 | ~13 pt |
| extraLarge | 1.15 | ~14 pt |
| extraExtraLarge | 1.28 | ~15 pt |
| accessibilityExtraLarge | 1.47 | ~18 pt |
| accessibilityXXXL | 1.71 | ~20 pt |
Pagpili ng relativeTo: gamitin ang .body para sa value na nauugnay sa pangunahing text (padding, spacing sa listahan), .title para sa malalaking elemento (iconSize, imageSize), .caption para sa maliliit na elemento (laki ng badge). Tinitiyak nito na ang mga elemento ay naka-scale kasabay ng nakapalibot na text.
Dynamic Type — iOS feature na nagpapahintulot sa user na ayusin ang system font size sa Settings → Display & Brightness → Text Size. Ang pagbabago ay inilalapat globally sa lahat ng apps. Ang @ScaledMetric ay awtomatikong tumutugon sa pagbabagong ito: ina-update ng SwiftUI ang lahat ng @ScaledMetric variable kapag nagbago ang UIContentSizeCategory.
Mahalaga: Ang @ScaledMetric ay nag-scale lamang ng numerical values, ngunit hindi direktang namamahala ng mga font. Para sa mga font, gamitin ang .font() na may text style (.body, .title, .headline) — awtomatikong nag-scale ang SwiftUI ng font. Kinukumpleto ng @ScaledMetric ang font scaling para sa padding, spacing at laki ng elemento.
Canvas Preview ay sumusuporta sa Dynamic Type: sa toolbar ng Canvas may slider na Text Size (A–A) para suriin ang UI sa iba't ibang laki ng font. Gamitin ito kasama ng @ScaledMetric para matiyak na tama ang pag-scale ng spacing at laki.
struct CardView: View {
@ScaledMetric private var cornerRadius: CGFloat = 16
@ScaledMetric private var spacing: CGFloat = 8
var body: some View {
VStack(spacing: spacing) {
Text("Pamagat ng card")
.font(.headline)
Text("Paglalarawan na may suporta sa dynamic type")
.font(.body)
}
.padding(spacing * 2)
.background(.regularMaterial)
.cornerRadius(cornerRadius)
}
}
struct CardView_Previews: PreviewProvider {
static var previews: some View {
CardView()
.dynamicTypeSize(.large)
.previewDisplayName("Large")
CardView()
.dynamicTypeSize(.accessibility5)
.previewDisplayName("Accessibility 5")
}
}
Ang cornerRadius ay nag-scale mula 16 pt hanggang ~27 pt sa maximum na accessibility size. spacing — mula 8 hanggang ~14 pt. Tinitiyak nito na ang card ay nananatiling balanse sa paningin sa anumang laki ng font.
Halimbawa: icon na may suporta sa Dynamic Type. Ang laki ng Image(systemName:) icon ay hindi naka-scale sa ilalim ng Dynamic Type bilang default. Nilulutas ng @ScaledMetric ang problemang ito: sa pamamagitan ng pagbabago ng imageScale o frame size batay sa kasalukuyang scale factor.
struct IconLabel: View {
let title: String
let icon: String
@ScaledMetric private var iconDimension: CGFloat = 28
@ScaledMetric(relativeTo: .body) private var spacing: CGFloat = 6
var body: some View {
HStack(spacing: spacing) {
Image(systemName: icon)
.resizable()
.frame(width: iconDimension, height: iconDimension)
Text(title)
.font(.body)
}
}
}
Halimbawa: naa-access na badge-component. Ang badge na may numero ay dapat mag-scale proporsyonal sa text. Ang @ScaledMetric para sa minimum na laki ng badge ay tinitiyak na ang bilog na badge ay nananatiling nakikita sa malaking font.
struct BadgeView: View {
let count: Int
@ScaledMetric(relativeTo: .caption) private var badgeSize: CGFloat = 20
@ScaledMetric(relativeTo: .caption) private var fontScale: CGFloat = 1
var body: some View {
ZStack {
Circle()
.fill(.red)
.frame(width: badgeSize, height: badgeSize)
Text("\(count)")
.font(.caption)
.foregroundColor(.white)
.scaleEffect(fontScale)
}
.fixedSize()
}
}
Ang fontScale ay nag-scale din ng nilalaman ng Circle upang tumugma sa pinalaki na badgeSize. Kung walang fontScale, ang text sa loob ng badge ay maaaring hindi magkasya sa malaking font.
@ScaledMetric at @State — parehong property wrapper na sumusubaybay ng mga pagbabago, ngunit may magkaibang pinagmulan ng update. Ina-update ng @State ang value sa programmatic na pagbabago (sa pamamagitan ng $stateBinding). Awtomatikong ina-update ng @ScaledMetric ang value kapag nagbago ang system Dynamic Type, ngunit hindi pinapayagan ang direktang pagbabago ng value mula sa code.
Ang pangunahing pagkakaiba: @ScaledMetric — read-only para sa developer at write-only para sa system. Hindi mo mababago ang scaledValue sa pamamagitan ng setter — kinakalkula ito ng SwiftUI batay sa base value at kasalukuyang Dynamic Type. Ang @State, sa kabaligtaran, ay ganap na pinamamahalaan ng developer. Kung kailangan mo ng value na parehong naka-scale sa ilalim ng Dynamic Type at nababago nang programmatically — pagsamahin ang @ScaledMetric sa @State o gumamit ng computed property.
| Katangian | @ScaledMetric | @State |
|---|---|---|
| Pinagmulan ng update | Dynamic Type (system) | Programmatic (developer) |
| Uri ng value | CGFloat, Int, Double | Anumang uri |
| Pagbabago mula sa code | Hindi maaari | Maaari sa pamamagitan ng binding |
| Muling pagguhit ng View | Kapag nagbago ang Dynamic Type | Kapag nagbago ang value |
| iOS bersyon | iOS 14+ | iOS 13+ |
Pinagsamang pattern: kung kailangan mong baguhin ang padding nang programmatically (halimbawa, animation ng pagpindot) at sabay na mag-scale sa ilalim ng Dynamic Type, gumawa ng @ScaledMetric para sa base scaled value at @State para sa animation multiplier. Ang final value = scaledValue × animationMultiplier.
Pagkakamali 1: paggamit ng @ScaledMetric para sa mga font. Ang @ScaledMetric ay nag-scale ng mga numero, hindi mga font. Para sa mga font, gamitin ang .font(.body) — awtomatikong inilalapat ng SwiftUI ang Dynamic Type. Huwag kailanman gumamit ng @ScaledMetric na may font(.system(size: scaledSize)) — sinisira nito ang system accessibility.
Pagkakamali 2: kawalan ng relativeTo para sa magkakaibang elemento. Kung mayroon kang padding (kaugnay ng .body) at iconSize (kaugnay ng .title), tukuyin ang tamang relativeTo para sa bawat isa. Kung walang relativeTo, parehong i-scale ayon sa .body, na magdudulot ng di-proporsyonal na paglaki ng icon kaugnay ng text context nito.
Pagkakamali 3: @ScaledMetric sa ViewModel/@ObservableObject. Ang @ScaledMetric ay SwiftUI property wrapper na gumagana lamang sa loob ng View. Hindi ito magagamit sa ViewModel o services. Para sa pag-scale sa ViewModel, ipasa ang scaled value mula sa View bilang parameter o gamitin ang @Environment(\.sizeCategory) sa View.
@Environment(\.sizeCategory) — alternatibong paraan ng pagkuha ng kasalukuyang Dynamic Type sa View. Gamitin ito kapag kailangan mo ng higit na kontrol: pagkalkula ng custom multiplier, pagpasa ng sizeCategory sa ViewModel, o pagsasama sa @ScaledMetric para sa flexible scaling.
struct CustomScaledView: View {
@Environment(\.sizeCategory) private var sizeCategory
@ScaledMetric private var basePadding: CGFloat = 12
private var extraPadding: CGFloat {
if sizeCategory >= .accessibilityLarge {
return basePadding * 0.5
}
return 0
}
var body: some View {
Text("Custom na naka-scale na nilalaman")
.font(.body)
.padding(basePadding + extraPadding)
}
}
Karagdagang spacing Ang extraPadding ay idinadagdag lamang sa accessibility size, na nagbibigay ng mas maraming espasyo para sa malaking text nang hindi binabago ang base @ScaledMetric logic.
Mga madalas itanong
@ScaledMetric — opisyal na property wrapper SwiftUI para mag-scale ng mga numero. @ScaledFont ay hindi umiiral bilang standard API — ito ay custom wrapper na ginawa ng komunidad. Para sa mga font, palaging gamitin ang built-in na .font() na may text style (.body, .title), at @ScaledMetric — para sa padding, spacing at laki.
Ang @ScaledMetric ay magagamit sa iOS 14+, watchOS 7+, tvOS 14+ at macOS 11+. Sa watchOS, ang Dynamic Type ay limitado sa mas maliit na range — mga laki mula .extraSmall hanggang .extraLarge nang walang accessibility size. Sa tvOS, wala ang Dynamic Type — palaging ibinabalik ng @ScaledMetric ang base value.
Oo, para subukan ang @ScaledMetric gumawa ng View na may @ScaledMetric at ipasa ang environment value na .sizeCategory sa pamamagitan ng .environment(\.sizeCategory, .extraExtraLarge). Pagkatapos, kunin ang laki ng elemento sa pamamagitan ng GeometryReader o SwiftUI Inspector. Bilang alternatibo, suriin ang scaling logic sa pamamagitan ng UIFontMetrics sa hiwalay na module.
.dynamicTypeSize — View modifier na naglilimita sa maximum Dynamic Type para sa hierarchy (halimbawa, .dynamicTypeSize(...large)). Isinasaalang-alang ng @ScaledMetric ang limitasyong ito: kung nakatakda ang .dynamicTypeSize, ang scaled value ay hindi lalampas sa kaukulang laki. Pagsamahin ang parehong API para sa tumpak na kontrol.
Tiyaking ang View ay gumagamit ng @ScaledMetric sa loob mismo (hindi sa ViewModel). Suriin na ang View ay naka-subscribe sa Dynamic Type: awtomatikong nagti-trigger ang @ScaledMetric ng body refresh, ngunit kung ang View ay gumagamit ng .equatable() o .id(), maaaring masira ang mechanism. Gamitin ang @Environment(\.sizeCategory) bilang fallback.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din