Animácie v SwiftUI: Kompletný sprievodca od pružín po KeyframeAnimator a PhaseAnimator

Kompletný sprievodca animáciami v SwiftUI — implicitné, explicitné, pružiny, prechody, PhaseAnimator, KeyframeAnimator a matchedGeometryEffect. Vrátane makra @Animatable z iOS 26 a tipov na výkon.

Prečo sú animácie v SwiftUI taký veľký deal

Animácie nie sú len ozdoba. Sú to nástroj komunikácie medzi vašou aplikáciou a používateľom — a úprimne, sú to často ten prvý dojem, ktorý rozhodne o tom, či aplikácia pôsobí profesionálne alebo amatérsky. Keď stlačíte tlačidlo a ono plynule zmení farbu, váš mozog okamžite pochopí, že sa niečo stalo. Keď sa zoznam presunie na stranu a objaví sa detail, intuitívne viete, odkiaľ ten detail prišiel.

Bez animácií sú rozhrania trhaná a mätúca. Proste to nefunguje.

SwiftUI robí animácie neuveriteľne jednoduché. Namiesto ručného počítania snímkov a práce s CAAnimation z UIKit sveta (čo bola, povedzme si úprimne, dosť otravná záležitosť) jednoducho poviete frameworku, čo sa zmenilo, a on vyrieši zvyšok. Od iOS 17 navyše pribudli PhaseAnimator a KeyframeAnimator pre viacfázové animácie, a v iOS 26 prišlo zjednodušenie cez makro @Animatable.

V tomto sprievodcovi prejdeme naozaj všetko — od úplných základov až po pokročilé techniky. Každý príklad obsahuje funkčný kód, ktorý si môžete skopírovať do Xcode a okamžite vyskúšať.

Implicitné animácie: Modifier .animation()

Najjednoduchší spôsob, ako pridať animáciu v SwiftUI, je modifier .animation(). Jednoducho ho pridáte za ostatné modifiery a poviete mu, aký typ animácie chcete a ktorá hodnota má animáciu spustiť. Nič zložité.

struct ImplicitAnimationView: View {
    @State private var scale: CGFloat = 1.0

    var body: some View {
        Button("Stlač ma") {
            scale += 0.3
        }
        .font(.title)
        .scaleEffect(scale)
        .animation(.easeInOut(duration: 0.3), value: scale)
    }
}

Parameter value: scale je kľúčový — a toto je vec, na ktorú začiatočníci často zabúdajú. Hovorí SwiftUI, že animácia sa má spustiť iba vtedy, keď sa zmení hodnota scale. Bez tohto parametra by ste dostali varovanie a nepredvídateľné správanie.

Dôležitý detail: od iOS 17 SwiftUI používa ako predvolenú animáciu pružinu (spring), nie lineárnu animáciu. Takže ak nezadáte konkrétny typ, vaše animácie budú mať príjemný, fyzikálny pocit. Osobne si myslím, že to bol jeden z najlepších rozhodnutí Apple v oblasti UI frameworkov za posledné roky.

Čo všetko sa dá animovať

Prakticky akýkoľvek modifier, ktorý mení vizuálnu vlastnosť view, sa dá animovať. Tu je prehľad tých najpoužívanejších:

  • .opacity() — plynulé zosvetlenie a stmavenie
  • .scaleEffect() — zväčšenie a zmenšenie
  • .rotationEffect() — otáčanie v 2D
  • .rotation3DEffect() — otáčanie v 3D priestore
  • .offset() — posúvanie po obrazovke
  • .frame() — zmena veľkosti
  • .foregroundStyle() — zmena farby textu
  • .background() — zmena pozadia

Explicitné animácie: withAnimation()

Alternatívou k implicitným animáciám je withAnimation(). Namiesto pripájania animácie k view poviete SwiftUI, aby animovalo konkrétnu zmenu stavu. Toto je obzvlášť užitočné, keď chcete jednou zmenou animovať viacero views naraz — a verte mi, toto budete chcieť pomerne často.

struct ExplicitAnimationView: View {
    @State private var isExpanded = false

    var body: some View {
        VStack(spacing: 20) {
            RoundedRectangle(cornerRadius: isExpanded ? 20 : 50)
                .fill(.blue)
                .frame(
                    width: isExpanded ? 300 : 100,
                    height: isExpanded ? 200 : 100
                )

            Text(isExpanded ? "Rozbalené" : "Zbalené")
                .font(.headline)
                .opacity(isExpanded ? 1.0 : 0.5)
        }
        .onTapGesture {
            withAnimation(.spring(duration: 0.5, bounce: 0.3)) {
                isExpanded.toggle()
            }
        }
    }
}

Všimnite si, že sme nemuseli pridávať .animation() modifier nikam. Stačilo zabaliť zmenu isExpanded do withAnimation a SwiftUI automaticky animuje všetko, čo na tejto hodnote závisí — veľkosť obdĺžnika, zaoblenie rohov, text aj priehľadnosť. Celkom elegantné, nie?

Kedy použiť implicitnú a kedy explicitnú animáciu

Toto je otázka, ktorú dostávam pomerne často. Použite implicitnú animáciu (.animation()), keď chcete animovať jeden konkrétny view nezávisle od ostatných. Použite explicitnú animáciu (withAnimation()), keď jedna zmena stavu ovplyvňuje viacero views a chcete, aby sa všetky animovali koordinovane.

V praxi zistíte, že withAnimation() použijete oveľa častejšie.

Pružinové animácie (Spring): Fyzika v službe UX

Pružinové animácie simulujú správanie fyzickej pružiny — objekt sa pohybuje smerom k cieľu, mierne ho preskočí a potom sa ustáli. Toto je najprirodzenejší typ animácie, pretože napodobňuje reálny svet. Apple ich považuje za natoľko dôležité, že v SwiftUI sú od iOS 17 predvoleným typom animácie.

A keď ich raz začnete používať, pochopíte prečo. Lineárne animácie oproti nim pôsobia strnulo a roboticky.

Moderná syntax (iOS 17+)

iOS 17 priniesol zjednodušenú syntax s parametrami duration a bounce:

// Pomalá a veľmi pružná
withAnimation(.spring(duration: 1.0, bounce: 0.7)) {
    offset = 200
}

// Rýchla a takmer bez odskokov
withAnimation(.spring(duration: 0.3, bounce: 0.1)) {
    scale = 1.5
}

Parameter duration ovplyvňuje vnímanú dĺžku animácie a bounce určuje mieru odskokov — hodnota 0 znamená žiadne odskoky, 1 znamená maximálne odskoky. Odporúčam si s týmito hodnotami trochu pohrať, kým nenájdete to „správne" nastavenie pre vašu aplikáciu.

Predvolené pružinové presety

SwiftUI ponúka tri pohodlné presety, ktoré pokrývajú najčastejšie scenáre:

// .smooth — plynulý, bez odskokov (predvolená pre väčšinu UI)
withAnimation(.smooth) { value.toggle() }

// .snappy — rýchly, s minimálnym odskokom
withAnimation(.snappy) { value.toggle() }

// .bouncy — výrazný odskok
withAnimation(.bouncy) { value.toggle() }

Každý z týchto presetov sa dá ďalej doladiť. Napríklad .bouncy(duration: 0.8, extraBounce: 0.3) vytvorí pomalšiu animáciu s väčším odskokom. Ja osobne najčastejšie siahnem po .snappy — je to taký príjemný kompromis medzi rýchlosťou a prirodzenosťou.

Interaktívna pružina pre gestá

Pre animácie riadené gestami existuje špeciálny modifier .interactiveSpring(). Gestá sú totiž kontinuálne — používateľ aktívne niečo posúva a cieľ sa môže meniť uprostred animácie. Interaktívna pružina je optimalizovaná presne pre tento scenár.

Circle()
    .fill(.orange)
    .frame(width: 80, height: 80)
    .offset(dragOffset)
    .animation(.interactiveSpring(response: 0.3, dampingFraction: 0.6), value: dragOffset)
    .gesture(
        DragGesture()
            .onChanged { gesture in
                dragOffset = gesture.translation
            }
            .onEnded { _ in
                dragOffset = .zero
            }
    )

Prechody (Transitions): Animovanie vzniku a zániku views

Kým .animation() a withAnimation() animujú zmeny existujúcich views, prechody (transitions) definujú, ako view vstúpi do hierarchie alebo z nej odíde. To je dôležitý rozdiel, ktorý si treba zapamätať.

struct TransitionView: View {
    @State private var showDetail = false

    var body: some View {
        VStack {
            Button("Prepni detail") {
                withAnimation(.spring(duration: 0.4, bounce: 0.2)) {
                    showDetail.toggle()
                }
            }

            if showDetail {
                Text("Tu som! 👋")
                    .font(.largeTitle)
                    .padding()
                    .background(.blue.opacity(0.2), in: .rect(cornerRadius: 12))
                    .transition(.scale.combined(with: .opacity))
            }
        }
    }
}

Dostupné vstavané prechody

  • .opacity — plynulé zosvetlenie/stmavenie
  • .scale — zväčšenie z/do nuly
  • .slide — posúvanie zo strany
  • .move(edge:) — posúvanie z konkrétneho okraja
  • .push(from:) — odtlačenie z konkrétneho smeru
  • .blurReplace — rozmazanie a nahradenie (iOS 17+)

Asymetrické prechody

Niekedy chcete iný efekt pri vstupe a iný pri odchode. Na to slúži .asymmetric():

.transition(.asymmetric(
    insertion: .move(edge: .trailing).combined(with: .opacity),
    removal: .move(edge: .leading).combined(with: .opacity)
))

Toto vytvorí efekt, kde view príde zprava a odíde doľava — niečo ako prezentácia. Vyzerá to naozaj pekne, hlavne v navigačných scenároch.

Vlastné prechody cez ViewModifier

Pre úplnú kontrolu si môžete vytvoriť vlastný prechod implementáciou ViewModifier. Je to trochu viac kódu, ale získate tým plnú flexibilitu:

struct RotateAndFadeModifier: ViewModifier {
    let isActive: Bool

    func body(content: Content) -> some View {
        content
            .rotationEffect(.degrees(isActive ? 90 : 0))
            .opacity(isActive ? 0 : 1)
            .scaleEffect(isActive ? 0.5 : 1)
    }
}

extension AnyTransition {
    static var rotateAndFade: AnyTransition {
        .modifier(
            active: RotateAndFadeModifier(isActive: true),
            identity: RotateAndFadeModifier(isActive: false)
        )
    }
}

Potom tento prechod použijete ako akýkoľvek iný: .transition(.rotateAndFade).

matchedGeometryEffect: Plynulé prechody medzi views

Toto je podľa mňa jedna z najlepších animačných funkcií SwiftUI. A som si istý, že keď to uvidíte v akcii, budete súhlasiť. matchedGeometryEffect umožňuje vytvoriť plynulý prechod medzi dvoma rôznymi views — niečo ako Magic Move v Keynote. View na jednom mieste zmizne a na inom mieste sa objaví, pričom SwiftUI automaticky animuje pozíciu, veľkosť a tvar.

struct HeroAnimationView: View {
    @State private var showDetail = false
    @Namespace private var animation

    var body: some View {
        VStack {
            if !showDetail {
                // Náhľadová karta
                RoundedRectangle(cornerRadius: 16)
                    .fill(.blue.gradient)
                    .matchedGeometryEffect(id: "card", in: animation)
                    .frame(width: 150, height: 100)
                    .onTapGesture {
                        withAnimation(.spring(duration: 0.5, bounce: 0.25)) {
                            showDetail = true
                        }
                    }
            } else {
                // Detailná karta
                RoundedRectangle(cornerRadius: 24)
                    .fill(.blue.gradient)
                    .matchedGeometryEffect(id: "card", in: animation)
                    .frame(height: 400)
                    .padding()
                    .onTapGesture {
                        withAnimation(.spring(duration: 0.5, bounce: 0.25)) {
                            showDetail = false
                        }
                    }
            }
        }
    }
}

Kľúčové sú tri veci: definovanie menného priestoru cez @Namespace, priradenie rovnakého id obom views a zabalenie zmeny do withAnimation. SwiftUI potom automaticky interpoluje medzi pozíciou, veľkosťou a tvarom oboch views. Naozaj to vyzerá magicky.

Prepínanie textu s matchedGeometryEffect

Pri animovaní views s textom je užitočné použiť parameter .properties nastavený na .position, aby sa text počas prechodu neorezával:

.matchedGeometryEffect(id: "title", in: animation, properties: .position)

Toto je taký malý trik, ktorý vám ušetrí dosť frustrácie pri ladení.

PhaseAnimator: Viacfázové animácie (iOS 17+)

Pred iOS 17 bolo vytváranie viacfázových animácií pomerne otravné — museli ste reťaziť withAnimation s oneskoreniami alebo používať Timer. Kto to skúšal, vie, aké to bolo krehké riešenie. PhaseAnimator toto celé zjednodušil. Definujete fázy, a SwiftUI automaticky cykluje medzi nimi.

Definovanie fáz cez enum

Najčistejší spôsob je vytvoriť si enum, ktorý popisuje jednotlivé fázy animácie:

enum AnimationPhase: CaseIterable {
    case initial
    case scaleUp
    case rotate
    case moveUp
    case reset

    var scale: CGFloat {
        switch self {
        case .initial, .reset: 1.0
        case .scaleUp: 1.4
        case .rotate: 1.2
        case .moveUp: 1.0
        }
    }

    var angle: Angle {
        switch self {
        case .initial, .scaleUp, .reset: .zero
        case .rotate: .degrees(360)
        case .moveUp: .degrees(0)
        }
    }

    var offsetY: CGFloat {
        switch self {
        case .initial, .scaleUp, .rotate, .reset: 0
        case .moveUp: -50
        }
    }
}

Použitie PhaseAnimatoru

struct PhaseAnimatorView: View {
    var body: some View {
        Text("🚀")
            .font(.system(size: 80))
            .phaseAnimator(AnimationPhase.allCases) { content, phase in
                content
                    .scaleEffect(phase.scale)
                    .rotationEffect(phase.angle)
                    .offset(y: phase.offsetY)
            } animation: { phase in
                switch phase {
                case .initial: .smooth
                case .scaleUp: .spring(duration: 0.4, bounce: 0.5)
                case .rotate: .easeInOut(duration: 0.8)
                case .moveUp: .bouncy(duration: 0.5)
                case .reset: .smooth(duration: 0.3)
                }
            }
    }
}

Animátor automaticky cykluje cez všetky fázy a pre každú fázu môžete určiť iný typ animácie. Bez triggeru sa animácia opakuje donekonečna — ideálne pre loading indikátory, onboarding animácie alebo dekoratívne pozadie.

Spúšťanie na požiadanie s trigger parametrom

Ak nechcete nekonečnú slučku (a väčšinou nechcete), môžete animáciu spúšťať manuálne pomocou parametra trigger:

struct TriggeredPhaseView: View {
    @State private var triggerCount = 0

    var body: some View {
        VStack(spacing: 30) {
            Image(systemName: "heart.fill")
                .font(.system(size: 60))
                .foregroundStyle(.red)
                .phaseAnimator(
                    AnimationPhase.allCases,
                    trigger: triggerCount
                ) { content, phase in
                    content
                        .scaleEffect(phase.scale)
                        .rotationEffect(phase.angle)
                } animation: { phase in
                    .spring(duration: 0.3, bounce: 0.4)
                }

            Button("Animuj") {
                triggerCount += 1
            }
        }
    }
}

KeyframeAnimator: Animácie po kľúčových snímkach (iOS 17+)

KeyframeAnimator je najsilnejší animačný nástroj v SwiftUI. A keď hovorím najsilnejší, myslím to vážne. Na rozdiel od PhaseAnimator, kde sa všetky vlastnosti menia súčasne medzi fázami, KeyframeAnimator umožňuje animovať každú vlastnosť nezávisle na vlastnej časovej osi. To vám dáva úplnú kontrolu nad choreografiou animácie.

Štruktúra animovaných vlastností

Prvý krok je vytvoriť štruktúru, ktorá drží všetky hodnoty, ktoré chcete animovať:

struct AnimationValues {
    var scale: CGFloat = 1.0
    var offsetY: CGFloat = 0
    var rotation: Angle = .zero
    var opacity: Double = 1.0
}

Definovanie kľúčových snímkov s KeyframeTrack

Každý KeyframeTrack animuje jednu vlastnosť nezávisle od ostatných. Máte k dispozícii niekoľko typov interpolácie:

  • LinearKeyframe — lineárna interpolácia medzi hodnotami
  • CubicKeyframe — plynulá Bézierova krivka (najčastejšie používaný)
  • SpringKeyframe — pružinový efekt s odskokmi
  • MoveKeyframe — okamžitý skok bez interpolácie

Poďme sa pozrieť na praktický príklad — animácia zvončeka:

struct KeyframeAnimatorView: View {
    @State private var animationTrigger = 0

    var body: some View {
        VStack(spacing: 40) {
            Image(systemName: "bell.fill")
                .font(.system(size: 60))
                .foregroundStyle(.yellow)
                .keyframeAnimator(
                    initialValue: AnimationValues(),
                    trigger: animationTrigger
                ) { content, value in
                    content
                        .scaleEffect(value.scale)
                        .offset(y: value.offsetY)
                        .rotationEffect(value.rotation)
                        .opacity(value.opacity)
                } keyframes: { _ in
                    KeyframeTrack(\.scale) {
                        CubicKeyframe(1.5, duration: 0.2)
                        CubicKeyframe(0.8, duration: 0.15)
                        SpringKeyframe(1.0, duration: 0.3)
                    }

                    KeyframeTrack(\.offsetY) {
                        LinearKeyframe(0, duration: 0.1)
                        SpringKeyframe(-30, duration: 0.15)
                        SpringKeyframe(0, duration: 0.4)
                    }

                    KeyframeTrack(\.rotation) {
                        CubicKeyframe(.degrees(0), duration: 0.1)
                        CubicKeyframe(.degrees(15), duration: 0.1)
                        CubicKeyframe(.degrees(-15), duration: 0.1)
                        CubicKeyframe(.degrees(10), duration: 0.1)
                        CubicKeyframe(.degrees(-10), duration: 0.1)
                        SpringKeyframe(.degrees(0), duration: 0.2)
                    }

                    KeyframeTrack(\.opacity) {
                        CubicKeyframe(0.5, duration: 0.15)
                        CubicKeyframe(1.0, duration: 0.15)
                    }
                }

            Button("Zazvoniť") {
                animationTrigger += 1
            }
            .buttonStyle(.borderedProminent)
        }
    }
}

V tomto príklade zvonček súčasne mení veľkosť, pozíciu, rotáciu a priehľadnosť — každá vlastnosť s vlastným časovaním a typom interpolácie. Výsledkom je komplexná a prirodzene vyzerajúca animácia zvonenia. Skúste si to v Xcode — efekt je naozaj presvedčivý.

Kedy použiť PhaseAnimator vs. KeyframeAnimator

Použite PhaseAnimator, keď máte diskrétne fázy a všetky vlastnosti sa menia spoločne. Je jednoduchší na pochopenie a rýchlejší na implementáciu. Použite KeyframeAnimator, keď potrebujete presné časovanie jednotlivých vlastností — napríklad pri notifikačných animáciách, onboarding efektoch alebo herných animáciách.

Vo väčšine prípadov vám bude stačiť PhaseAnimator. Po KeyframeAnimator siahajte, keď naozaj potrebujete tú extra úroveň kontroly.

Makro @Animatable v iOS 26: Menej boilerplate kódu

iOS 26 priniesol zmenu, ktorú som osobne čakal dosť dlho. Predtým ste museli manuálne deklarovať animatableData v každom view alebo shape, ktorý ste chceli animovať. Bolo to otravné a náchylné na chyby:

// Starý spôsob (pred iOS 26)
struct PulsingCircle: Shape {
    var progress: CGFloat

    var animatableData: CGFloat {
        get { progress }
        set { progress = newValue }
    }

    func path(in rect: CGRect) -> Path {
        let radius = rect.width / 2 * progress
        return Path(ellipseIn: CGRect(
            x: rect.midX - radius,
            y: rect.midY - radius,
            width: radius * 2,
            height: radius * 2
        ))
    }
}

S makrom @Animatable jednoducho označíte struct a makro automaticky vygeneruje celú implementáciu animatableData za vás:

// Nový spôsob (iOS 26+)
@Animatable
struct PulsingCircle: Shape {
    var progress: CGFloat

    func path(in rect: CGRect) -> Path {
        let radius = rect.width / 2 * progress
        return Path(ellipseIn: CGRect(
            x: rect.midX - radius,
            y: rect.midY - radius,
            width: radius * 2,
            height: radius * 2
        ))
    }
}

Toto výrazne znižuje bariéru pre vytváranie vlastných animovateľných shapes. Nemusíte si pamätať syntax animatableData a pri viacerých animovateľných vlastnostiach nemusíte pracovať s AnimatablePair (čo bol, úprimne povedané, dosť nepríjemný API pattern).

Opakovanie, oneskorenia a kombinácia animácií

SwiftUI ponúka modifiery na jemné doladenie správania animácií. Poďme si prejsť tie najdôležitejšie.

Opakovanie animácie

// Opakovanie 3-krát s odrazom
.animation(
    .easeInOut(duration: 0.5)
    .repeatCount(3, autoreverses: true),
    value: isAnimating
)

// Nekonečné opakovanie
.animation(
    .easeInOut(duration: 1.0)
    .repeatForever(autoreverses: true),
    value: isAnimating
)

Oneskorenie

// Animácia s oneskorením 0.5 sekundy
.animation(
    .spring(duration: 0.6, bounce: 0.3)
    .delay(0.5),
    value: isVisible
)

Kaskádové animácie v zoznamoch

A teraz niečo, čo vyzerá naozaj dobre. Kombináciou oneskorenia a indexu vytvoríte elegantný kaskádový efekt:

struct CascadeView: View {
    @State private var isVisible = false
    let items = ["Swift", "SwiftUI", "Xcode", "iOS", "macOS"]

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            ForEach(Array(items.enumerated()), id: \.offset) { index, item in
                Text(item)
                    .font(.title2)
                    .padding()
                    .background(.blue.opacity(0.15), in: .rect(cornerRadius: 10))
                    .opacity(isVisible ? 1 : 0)
                    .offset(x: isVisible ? 0 : -50)
                    .animation(
                        .spring(duration: 0.5, bounce: 0.3)
                        .delay(Double(index) * 0.1),
                        value: isVisible
                    )
            }
        }
        .onAppear { isVisible = true }
    }
}

Tento pattern sa hodí prakticky všade — zoznamy, nastavenia, onboarding obrazovky. Je to jeden z tých malých detailov, ktoré robia aplikáciu príjemnejšou na používanie.

Tipy na výkon animácií

SwiftUI robí animácie jednoduché, ale výkon nie je automatický. Tu je niekoľko pravidiel, ktoré vám pomôžu udržať plynulých 60 fps (alebo 120 fps na ProMotion displejoch):

  • Preferujte transformácie pred zmenami layoutu. Modifiery ako .scaleEffect(), .rotationEffect() a .offset() sú GPU-akcelerované a nespôsobujú prepočítanie layoutu. Animovanie .frame() je výrazne drahšie, pretože vyžaduje prepočítanie celej hierarchie views.
  • Používajte .drawingGroup() pre komplexné views. Tento modifier rasterizuje view do jednej vrstvy pred animáciou, čo výrazne zlepšuje výkon pri mnohých subviews.
  • Obmedzujte počet súčasne animovaných views. Ak animujete dlhý zoznam, zvážte animovanie iba viditeľných prvkov.
  • Využívajte @Observable pre granulárne aktualizácie. V kombinácii so Swift 6 a iOS 26, @Observable zabezpečuje, že sa prekreslia iba views, ktorých dáta sa skutočne zmenili.
  • Testujte na reálnom zariadení. Simulátor v Xcode beží na výkonnom Macu a nezobrazí problémy s výkonom, ktoré sa objavia na staršom iPhone. Toto platí dvojnásobne pre animácie.

Často kladené otázky

Aký je rozdiel medzi implicitnou a explicitnou animáciou v SwiftUI?

Implicitná animácia (.animation() modifier) sa pripája priamo k view a reaguje na zmenu konkrétnej hodnoty. Explicitná animácia (withAnimation()) zabalí zmenu stavu a animuje všetko, čo na tejto zmene závisí. Použite implicitnú pre izolovanie jedného view a explicitnú pre koordinované animácie viacerých views.

Prečo SwiftUI používa pružinovú (spring) animáciu ako predvolenú?

Od iOS 17 je predvolenou animáciou pružina, pretože simuluje fyzikálne správanie reálneho sveta. Na rozdiel od lineárnej animácie, pružina prirodzene spomaľuje pri cieli a môže mierne presiahnuť, čo vytvára pocit živosti a autenticity. Apple odporúča pružiny pre väčšinu UI animácií, pretože výsledok pôsobí na používateľa intuitívne.

Kedy použiť PhaseAnimator a kedy KeyframeAnimator?

PhaseAnimator je ideálny pre jednoduché viacfázové animácie, kde sa všetky vlastnosti menia spoločne medzi diskrétnymi stavmi. KeyframeAnimator použite, keď potrebujete presné časovanie a chcete animovať každú vlastnosť nezávisle na vlastnej časovej osi. Pre loading indikátory zvyčajne stačí PhaseAnimator, pre komplexné notifikačné alebo hero animácie siahnite po KeyframeAnimator.

Ako vytvoriť hero animáciu medzi dvoma obrazovkami v SwiftUI?

Použite modifier .matchedGeometryEffect(id:in:). Najprv vytvorte menný priestor pomocou @Namespace, potom priraďte rovnaké id obom views — zdrojovému aj cieľovému. Zmenu stavu zabaľte do withAnimation(.spring()) a SwiftUI automaticky animuje pozíciu, veľkosť a tvar medzi oboma views. Pre text nastavte properties: .position, aby sa počas prechodu neorezával.

Čo je nové v animáciách pre iOS 26?

iOS 26 prináša makro @Animatable, ktoré automaticky generuje implementáciu animatableData pre vaše vlastné shapes a views — výrazne redukuje boilerplate kód. Okrem toho systém Liquid Glass s GlassEffectContainer umožňuje plynulé morphing animácie medzi UI prvkami. Navigačné prechody sú teraz prerušiteľné, takže používateľ môže interagovať s obsahom bez čakania na dokončenie animácie.

O Autorovi Editorial Team

Our team of expert writers and editors.