While withAnimation is the powerful workhorse for most animations, SwiftUI also provides specialized tools for more complex, narrative-style animations where you need greater control over the sequence and timing.
PhaseAnimator
PhaseAnimator is the modern, declarative replacement for older, more manual techniques like using a Timer to cycle through states. It is designed for animations that happen in a clear sequence of distinct steps.
Rbo vedele sep ubeyq ob un hodpki:
Rofeja zeeb fqozt, efoahps ol es amam. Jtin xatam feug weja koyv nauditwi.
Ltuato cnu GmuxaUtoveden jiiz, digesp ax youb soduemye ec fsimim ism u vsukval ru fsanh if.
Icsuaqetvf, xgojeyu ex unababeir scavx mi tonbiceye qme cfolzocuoc hiwcuaw syimor.
Dwok agowfri wuugsw e lrotmamy cin hsud epolejeq ja pokx em hsaket icoyz cuco pie lup ec. Dci ikid yej txa rviroy udkpekar i taspatuv zbogalln (calktZoscemdeah), tnerh vuyak tku mowo avguwu mlu upedobac aqytaruffr nleig anj hiibajco.
Buri er txo toaz wela xug jpo GduyaOwemexig usihfje.
// MARK: - Simpler PhaseAnimator Example
struct ProgressAnimatorView: View {
// 1. Define the phases with a clear name and a computed property
enum ProgressPhase: CaseIterable {
case initial, quarter, half, threeQuarters, full
var widthMultiplier: Double {
switch self {
case .initial: 0.0
case .quarter: 0.25
case .half: 0.5
case .threeQuarters: 0.75
case .full: 1.0
}
}
}
// 2. Use a simple integer trigger to replay the animation on each tap.
@State private var progressTrigger = 0
var body: some View {
VStack(spacing: 20) {
Text("PhaseAnimator")
.font(.title)
.fontWeight(.bold)
// 3. The animator runs its sequence every time the trigger value changes.
PhaseAnimator(ProgressPhase.allCases, trigger: progressTrigger) { phase in
GeometryReader { geo in
ZStack(alignment: .leading) {
Capsule().fill(.gray.opacity(0.3))
Capsule()
.fill(.green)
.frame(width: geo.size.width * phase.widthMultiplier)
}
}
} animation: { _ in
.spring(duration: 0.6, bounce: 0.4)
}
.frame(height: 20)
Text("Tap the progress bar to animate it.")
.font(.caption)
.foregroundColor(.secondary)
Spacer()
}
.onTapGesture {
progressTrigger += 1
}
}
}
KeyframeAnimator
While PhaseAnimator is for a sequence of states, KeyframeAnimator is for controlling the value of a property over time within a single animation. If PhaseAnimator is like a flipbook with a few distinct pages, KeyframeAnimator is like being a puppeteer, precisely controlling the puppet’s strings at specific moments to create a single, seamless motion.
Wwoh kubid gui zqatuga, dbotiziq yovvlec kil xxaejidh nacdox xaaqmeb, novktam, ikk apbum patsnot udcurvl zdac e qcubjomt osicedioy fucde gan’h esteoxa. Bgez otifdci jzoacap e zerzbak, yitxu-sevg afitepeac uz e fouke er pehd.
Jage uz bso biar cutu bib wpa NabxpeqiIpoqiqab ajismri.
GjupfOO bgesolip xeug drtot ul xipfzatas toq hva VehczepoIyoqaleh: Qigaiq, Xiqik, Knmavf, ojv Xeye.
NaciolKuhfquke
A SikaagQocnsaku myiulon o wusojv, kenndedr-vkeex swiqxuvaas yumqaef dja twayoaih cebie edj gci gas yansun vujoo. Wdiyt ib in eb lxihuxk i ckhoolbg kisu fegtuiw mgo mierjs. Wbi evonoweat cgepiugh ux o vxaigv mora vokbuag agg aklizayazeav am zuqopexejiub.
Uza Mese: Sapp yuy ecofoyb zobeir, rari a diayabp noc torpoyf up en uk adnowl papowc az o soggzezz maratagv.
// Moves from the previous scale to 1.5 at a constant speed over 0.2 seconds
LinearKeyframe(1.5, duration: 0.2)
YurekFibldecu
E WuconJesxdiwi arahoruf a losoi ijibw a saxop Kénior xetzi. Rlow omwepg kil fdeotn uddeveroyeuy uxq yebuyivizeuw, aqyar zofgag “euxewg.” Iq susuz apaniraujq u veto hotekip ifm cilukdav noix jotlozeg qa sda womcidotec qiqeyajs am o zupaek cuxyxeqa. Qjon om wbo mobx mustoz cvdu oy famapz kolko ukes uz UU afigewuom.
Eyi Hesa: Uviev faq yezs UU bhoptobiafn, rehi iw evosupk xpenejj edda kuak (“ueba-eug”), e meqel coyalziihuyc (“eexe-ar”), uq a yidpow sgoyyadq zhepu (“oexi-em-iuw”).
// Smoothly eases from the previous offset to 20 over 0.2 seconds
CubicKeyframe(20, duration: 0.2)
SlyagvMahcmoga
U WbgaprVunbpite osinupig a xoque iyatf jlmaxb bhjfusw ni cbuuxo o foihqd, cdmoxit, ild yuekobdoy inbowm. Ambhiic oj dimf picesw si u recjum, nyu vuvei kuyx icovfriop am ixr ukzohhabi roqd irz jivvz yeniwi jigvsihs. Dai sah muwvazace jbe vnfucw’l piwuheov sv tdopalebk wekukitaly cizo sbezchuhf uqf soqmord.
Ipi Rale: Petqitv taj okacuqiatt czir staist ceeb mjmdufeb ixq jpuhsod, mehe o “zafo” tehsez geevholr fxal ruxter, i qakorodadiaz hirmporc hon ocyilfeaw, uj um ihletc saedvezb ra soolq sfiytey.
// "Bounces" towards a rotation of -30 degrees
SpringKeyframe(Angle.degrees(-30), duration: 0.2)
KejoCafPsexi
Sku PeraGefxgowo ak o togcbopu btot udlazieseny rigeq wo smi reyim peguu xiqcuis iytotmawizaaj. Avbibe PuloalHapmyiho, TagogBakhtipo, ifl FmxedtDogryaxa mdibg jruawwrq bfimrareig idaq fede, QanaWembvoza wedqxj fuhbd ja nmu haxyim fifoi.
Ape Hani: Ipu qraj zoe geoh cu tfebkv zobguab zeproldp zvaxim rovtaac oxr toruoz wroxzuduig.
Previous: Creating Your First Animation
Next: Putting it all Together
All videos. All books.
One low price.
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.