@ScaledMetric — ano ito, property wrapper SwiftUI at Dynamic Type

May-akda: IT Sectr Nai-publish: 2026-06-27 Oras ng pagbabasa: 10 min

@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 para mag-scale ng value sa ilalim ng Dynamic Type.
  • Dynamic Type — system setting ng iOS na nagbabago ng font size mula sa UIFontTextStyle.
  • Pag-scale — @ScaledMetric tumatanggap ng base value at relativeTo multiplier.
  • Awtomatikong update — kapag nagbago ang Dynamic Type, @ScaledMetric ay muling kinakalkula at nag-a-update ang UI.
  • Accessibility — ang paggamit ng @ScaledMetric ay nagpapabuti ng accessibility ng interface nang walang karagdagang code.

Ano ang @ScaledMetric?

@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.

Syntax ng @ScaledMetric

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.

swift
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.

Paano gumagana ang @ScaledMetric

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 scaling scale ng Dynamic Type

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 CategoryCoefficient (body)Halimbawa @ScaledMetric(12)
extraSmall0.85~10 pt
small0.93~11 pt
medium (default)1.0012 pt
large1.07~13 pt
extraLarge1.15~14 pt
extraExtraLarge1.28~15 pt
accessibilityExtraLarge1.47~18 pt
accessibilityXXXL1.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.

@ScaledMetric at Dynamic Type

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.

Pagsusuri ng accessibility sa pamamagitan ng Canvas

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.

swift
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.

Mga halimbawa ng @ScaledMetric

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.

swift
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.

swift
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 vs @State — pagkakaiba

@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 updateDynamic Type (system)Programmatic (developer)
Uri ng valueCGFloat, Int, DoubleAnumang uri
Pagbabago mula sa codeHindi maaariMaaari sa pamamagitan ng binding
Muling pagguhit ng ViewKapag nagbago ang Dynamic TypeKapag nagbago ang value
iOS bersyoniOS 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.

Mga karaniwang pagkakamali sa @ScaledMetric

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.

Pagkuha ng kasalukuyang sizeCategory sa code

@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.

swift
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

Paano naiiba ang @ScaledMetric sa @ScaledFont?

@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.

Gumagana ba ang @ScaledMetric sa watchOS at tvOS?

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.

Maaari bang subukan ang @ScaledMetric sa unit-test?

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.

Paano nakikipag-ugnayan ang @ScaledMetric sa .dynamicTypeSize?

.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.

Ano ang gagawin kung hindi ina-update ng @ScaledMetric ang UI?

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

  • @ScaledMetric — property wrapper SwiftUI para sa awtomatikong pag-scale ng numero sa ilalim ng Dynamic Type.
  • Pagkakatali — relativeTo ay nagtatali ng scale sa partikular na text style (body, title, caption).
  • Accessibility — pinapabuti ng @ScaledMetric ang accessibility ng interface nang walang manual na code.
  • Numero lamang — ang wrapper ay nag-scale ng CGFloat, Int, Double, ngunit hindi mga font.
  • Saklaw — mula 0.85 (XS) hanggang 1.71 (XXXL) kaugnay ng base value.
  • Read-only — hindi mababago ang @ScaledMetric mula sa code, sa pamamagitan lamang ng system.

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.

Pag-usapan ang proyekto

Basahin din