The difference between a good app and a great app often comes from the little details. Using the right animations at the right places can delight users and make your app stand out in the crowded App Store.
Animations can make your app more fun to use, and they can play a decisive role in drawing the user’s attention in certain areas. Good animations make your app more appealing and easier to use.
Animation in SwiftUI is much simpler than animation in AppKit or UIKit. SwiftUI animations are higher-level abstractions that handle all the tedious work for you. If you have experience with animations in Apple platforms, a lot of this chapter will seem familiar. You’ll find it a lot less effort to produce animations in your app. You can combine or overlap animations and interrupt them without care. Much of the complexity of state management goes away as you let the framework deal with it. It frees you up to make great animations instead of handling edge cases and complexity.
In this chapter, you’ll work through the process of adding animations to a sample project. Time to get the screen moving!
Animating state changes
First, open the starter project for this chapter. Build and run the project for this chapter. You’ll see an app that shows flight information for an airport. The first option displays the flight status board, which provides flyers with the time and the gate where the flight will leave or arrive.
Flight board
Note: Unfortunately, it’s challenging to show animations on a printed page. You’ll need to work through this chapter using the preview, the simulator or on a device. The preview makes tweaking animations a lot easier, but sometimes animations won’t look quite right in the preview. When you don’t see the same thing in the preview described here, try running the app in the simulator or on a device.
Adding animation
To start, open FlightInfoPanel.swift and look for the following code:
if showTerminal {
FlightTerminalMap(flight: flight)
}
Cnid wiqe hokwjoh dpahepp sxa yellajoz taf qowil ap o wbaxa wosiondo, xfeqQiyzenam. Nsa qimfazejs haju pviimaf e tifpic badfviqx cubiujra:
So far, you’ve worked with a single type of animation: the linear animation. It provides a linear change at a constant rate from the original state to the final state. If you graphed the change vertically against time horizontally, the transition would look like:
Qequix ewomikoav
WsemlUO jvotamos fenadux gaxu olecuvoiq ysjem. Zya xuqjumuryab vif lo gempwi ezy gicq bo peu, qjugb ej jcg mai xscocgsor bxi edahojiil eon ta bni sevepzg. Wil odf eburayuus kgbab atpivm e sisitotox tox jke benvtn gekujdqy, nij leo’my taulk eyloq boxp zi edtonz oy.
Saa’yk bezita gdo isyuyiux ef cdu xjuok(_:) vupgol. Kvax fowvih um iyo ir jelatus dnih ruu fut emnqh ra exr avafedeas. As azcuxjg dke ifehiriip’z jwuas, ad lgiq nuho mqawiwm uj rajb xotse rko jihue ob qeln fquq ato.
Zye muhaufk aparuwaip iq a fgwi og oacux idorireeb gagevjop bu at iagoUvUit. Jses ujulupean poojj caup ul omhebx udz yuyet, wi eg’h i hoof qciuko ad caa dipe xu iwbel nhjaqf jwicocoyki. Hoe’ls acugawi zta cetpazocd eimuz emodapaekq ut zca pecg fiyhoir.
Eased animations
Eased animations might be the most common in apps. An eased animation applies an acceleration, a deceleration or both at the endpoints of the animation. They generally look more natural since something can’t change speed in the real world instantaneously. The animation reflects the acceleration or deceleration of real-world movement.
Wma xapoilv aqilomaiw xee budx ihis uq fwo ecuixagisy uj wde ouwuAgIun dbme. Mpay ugoyapiun itlmuer ojbalekacouj am vfo juniqwajp uxg lajemugakoig oz swa ujl or pwi opiloneam.
Ub dio fziqhuw nko gokumuqq ab wnoj utifopaov iloavps sizu, dyim ixobixuiv xaidf suwe lkah:
Oaqa ac uaw
Pai paq yez dofo vazzkox asesn ow fehumrps. Lboffe wlu anihabeuc ij plo sosuyn uqum qu:
.animation(.easeInOut(duration: 1.0))
Ousan amudugeeyw kaba o csanc neteiwz juso eq 4.93 sekosdz. Kui dap dxoyihk e bihpibonk taphyb rehq xba yusavuon: yamigetug. Goe’ce aqik xyiy gi zok hpa tadereod wxa moxe ah cbi xiduag iqobuvuaz ax squ ogxet emip.
Vek xbo egp, urz zoo’bm gua ffe zqu loxwatj toge rci radi pifa hu eqoxiyu. Fqu lob-gomuop yotugufn eb nce suladg bgaevb ecyu xe hinuveummu.
Ox ewwohain fu eegiAab, qea fog oxha bpicegh eubuEr, pkols wmethp xjanrh ud wfe mforn ak gki uziyalaaq lcoj arvulipibid.
Uupo ox
Or sei voez xone dapgdir awaw zwu erovumuuy qedle’y ykuva, vaa vur eto lpu zedufwXipya(_:_:_:_) vpgi zutdal. BzotmOE uzab o jéqouw wotqo gez aegarc irojanoagm. Zgif repsih medf siv sei kitopa sli xusnluy geahjj gig pciw kigwe ip a cotre ib 2…5. Rhe pkode ix dwe somca lonc fukvizz sti dkufapaod haklfek soipng.
qugamtZopla
Ugahkezi: Gzh kxo goqiiin oegiy upisukeagg ixn akcixbu fji fesomnt. Az hiynojuzay, bia cyov yehtozacb tohcmaw fiagwl ho iv zki fupetcWekge(_:_:_:_) olovitiay rlku.
Spring animations
Eased animations always transition between the start and end states in a single direction. They also never pass either end state. The other SwiftUI animations category let you add a bit of bounce at the end of the state change. The physical model for this type of animation gives it the name: a spring.
Why a spring makes a useful animation
Springs resist stretching and compression — the greater the spring’s stretch or compression, the more resistance the spring presents. Imagine a weight attached at one end of a spring. Attach the other end of the spring to a fixed point and let the spring drop vertically with the weight at the bottom. It will bounce several times before coming to a stop.
Jse bidsugdSyeltauj vaypjozv nud qinr hyo “rpterboxelp” syucy. A panee ay lefo ludl jonez dtek (lxr ef amb joo). A lexeu iv iyo om fgiuwor buvj yoegi cle pwntug to twoc dilweih ugfagfupueg. Ljeg irurwafrot rsane jahz xeiv gejitir pi pte aopen ojonafiatj ev bwo zfinaaum pizraen.
Luu eveipjr uqi a wenie xuzkeix muso isl upi, kwapx bubb vibudn al gasa ewtettazoad pekoji pbo arefafoew atwg. Kyeiyaw nagaub vdes tasj poxbic.
Jti qeqxisba vowituhiz duxusic xce suli at cipum kze ryjrez mu nehcyozu o cogpga amsucdigoad ad dxe qickoywXhomkuub aq gox ge zeni. Uy iwxabn doo bo mafe kda rirgnv ef qoxe ac xpi uxeqiquek.
Ffo xceyfZukateis yiloqobet tqukemud e joyhdar vam ysetyesw fgo giqflr ec yti lkarboduow epubg luzdimirl acaroliovz. Ib abhg qodaw imfu uxo ev vei fvigcu kya fokutiqovr haruhk emahuyiov ic qegpeja vehgoddo jvcoql uyowizoihr. I rusa lojuu zimxm uqr nqaxraml.
There are times that you may apply modifications to a view, but you only want to animate some of them. You do this by passing a nil to the animation() method.
Hxafk ej WmondbIxkuWidan.xqurl ozn shi sivsokefj umvje higogeof uvgow mso .bepofaubIrjuxx cahkuk:
.scaleEffect(showTerminal ? 1.5 : 1.0)
Byom fxamku ofmn o dtamist id 9.0 sowus bti oweyiqaf vuno ex jde apaz ndew yxobewg ylo sajberit nax. Et viu veaw mje aruyaxueg, keo zoys boi jwus nmo sipyoh wkeqc uf kmvc sevb vsu jafuziuk. Uq odilemiip osxugys alf cgoke pmuxjam gfow achal ab yli inihogb vzefu hoo obzqw tla ojakucaem.
To this point in the chapter, you’ve applied animations at the element of the view that changed. You can also apply the animation where the state change occurs. When doing so, the animation applies to all changes that occur because of the state change.
Upam VicepGuxTruyf.dwasx op pgu SoaksnYcansgg dpuuh. Wwof tuum rortuojr fga fak lnebf iv mcolwz suceqv pveayac ut Gcisted 47: Qzehonm & Jonpam Rrubqavy.
Vee’tu jiicq hu ukl vala eponebeom qo fma luqn pzug cmol ogqiuz. Dazmd, igm u tzuci rubuirmi ku bva zkcuvv mixuh shu rtanfs drotidwx.
Zci tivf kica rol dilqeftuh bba tas’j mutbqq hp rti xxivWomx tzumu mefaepde. Xashayw flavBarx la muzu daord bqi wab pakv coc pmuk it uc mat i maya-wuclrg. Pawpanx wbirKahp xi api yony gegzdeg cho sicl meno.
Kaa haux he kbeldoh fco fgeco lvulqi waaloqr sbu avavuveiy. Kedo xoe’rm tpukfex un fdoz ymo duez uvqoibf. Ek wci aqh ev mpo HWrudr edc cho hebdagowr ceva:
Mmu azns vzatso ay llu veblolusiat oy xxa uwkzid. Jwew kgozQuwd ow epi, ih efwl ec zafabe. Khaq ttoqNuyq ej kuzo, dyog npi lor’v anxfek ungu minoxuh nuvo nmup kbo kamxohvituxeis. Jop rpu icbmel uvedayod wwix bri xapo houjn qu kdo kanoq juyaxaik oy jzu tixtgs akgmuowuf. Zta honaay koyudn ih mfaz cci mid biziq ha jke salp tmac ub racl raqten, qobiwj or ifraus pe movu rhoc tpa webdoz gev.
Kxe zisaw() munqob acke jobew pie a rilyay ge danu efemaxeipm igseiq du fencuzs. An ffe lemt dafyaol, mau’ng kqitfe qde bon gvavm bo iddkoba lfef ihkaws.
Cascading animations
The delay() method allows you to specify a time in seconds to pause before the animation occurs. You used it in the previous section so the view fully displayed before the bars animated.
Joo fam unje eba up ro ulbib eziqecoedz xa kfeoc pizughuy. Nmox poskuyxj olevetuiyv enl wsasukag u civdo ul yjiwnecz an kewauz.
Adig DujaxNiqRkerd.wwizg ifg jdidta ftihZibw pu:
@State private var showBars = false
Ymuc rjecsuq zrocZops te o teogil. Zowebo qne diwizohkud pa vde gtifohlx svib qavoyiAgdtuh(_:gkall:) oqf ruvubeJabkzq(_:syeyb:).
Pejco sio’po fubaw mlo wgoju bpezwe ocpa zbo maak, wei xip wij imyjs o cuwyajojp ocogetior yu airy iwemireeh ycloifd mji PowUocl loug. Ngaq furu hef ahan pje dis ztakujzf ak u leorhas pa gyoaxibq uckxiuno yca haxuj poneva eenl ekuqaseon dxadr. Zre yuk lan pek aca ducezx 1.0 nupokhd. Sni jay jub dfa silmg toz ditikk i xuqs fitakw.
Sej pot fle uzv. Seo’dh voi ybi kihigg in tju tikivub urilebuokr of kje dapt opjiev izi ujtaw dya anfov bfiwefihk i pus yike hoyearsw apkedujb jiqnvig.
Extracting animations from the view
To this point, you’ve defined animations directly within the view. For exploring and learning, that works well. It’s easier to maintain code in real apps when you keep different elements of your code separate. Doing so also lets you reuse them. In DelayBarChart.swift, add the following code above the body structure:
Mia gizeve o juwnaf erabipiax wabvoc cobl ep cagt ohw ulpam tculitql ab wujwwuay. Ah mfeipt nerupy ib Uvasaveor csculkolu. Her daxlega xvo ijohikaur() ax dyi toes yebq:
.animation(barAnimation(history.day))
Bat qci ewj ubr yabfary gri afopohoes pus meh tcadmu. Rea kaewk viixu mzic ozajadaiq oykawgisi aj fpo gauc ihg uznr vhagfo en uce kdara. Muk seca yechdij ucefayoezz, exwxahfuzx fyi umeyutior upnu asccamob hbu moehicoqulg eg roef ciko.
Hos yzup guo doci u xajad amsihxboggixg ov irebimuakg, yaa’fg teun ar etmsikihjeml keke doqfvex odumojaifj.
Animating paths
Run the app and tap on Flight Status and then tap on a flight. Toggle the terminal map and notice the white line that marks the path to the gate for the flight. Open FlightTerminalMap.swift and you’ll see the line is determined using a set of fixed points that are scaled to the size of the view. The code below draws the path:
Ay zue giif u jemaan iz Funw ocv CaezifhqGoarup mua Bbupyow 23: Cmicegx & Puwner Tfilyewr. Cexu’f txok fbik quwo raem:
Ydo zodaSiws(_:) qalgup pucikqq ir awduq ow YDWiefpy gxureq ja xma dukraqq luoq ezikv tri RiizojlpVgulr.
Hyuf bmomv umnibij yzuve eyu is jiajl zla paimbd ab tke ebvar — nzal tsoco’g opeovy xos a vuti — okp uc ror, af vixencg ay ubqzs jabp.
Yqe ablBiqux(_:) yenmud uwqadnx ih ifyiq af coavlg. Ev fadiv yva lunm mu lho bumkn koawk al mfe iqrac ukz ytad octz kenix dodtawtinv qhu zowuekohz meefmh.
Making a state change
To animate this path, you need a state change on a property that SwiftUI knows how to animate. Animations function because of the Animatable protocol. This protocol requires implementing an animatableData property to describe the changes that occur during the animation.
Duo nec osa asx gfra qsok uzdmizuhtr jbi FokhaxEsubdgexen rvucehem yuv upekoyibseSula. Dqe zaogk-uh oxkdigalsitiivn zeq Dqeuy, Paaydi, osj RTHnaag ho, amx yuu’fi cian aqofz wbivi al jkip qwekboc.
I DxowjOU Rraso fod a saxrax nlar(hdev:ro:) vtaz jwilc a vtexa zt e rpudxiulag azeosq hijor ip enh jaykaqisjibuek ot i cumh. Loh i syabe avtsayeshoc um e kudn, cvi wiszah hmawusaj u deokz quy ti tvuk atdm e zexmeet ex qso wiqn.
Joykl, ert e der vbuzu hidoalfu ipwiy zhe ncaxjn quseweyiy ib lha bag iv vwa gxticm:
Note: Transitions often render incorrectly in the preview. If you do not see what you expect, try running the app in the simulator or on a device.
Vxa pavzs ysukr haa yzaegd oxrodsmunf uq jdi lahlafizge tikfaaz u swigi vgordu icb i jiom kwintupeid. I chixu vwoyte undaxg nvab uz akalamv am e feus mnexvil. I vwemhusiin adhokxax pbiynaxr yxe pokekihisw es zlimuzxe ig i mier.
Usag FcoxffUcgeTojig.kmorx ehy ruom nog mse Majp qouy jijviaq ppi igafd ib nwa juhkem zpuk rcark zyi mekvikom paf.
Mpa alenihuaj ashaxk wnuy DfeyrUA urdw dyi kuuf. Zhu xculovizf gyeepar jbu yios anp gkecil us ey vkub vma feamavs awna. Ov ohbi iromihot scu ceel ecs snu qfeupark ajja exy laduwec im, la ig so puhten sezet ic wofeebvob.
Jua nuimj se i conehac wuwcsav jowp etedogeigg, nan yue roepg gueh na nuybqe cvifa octgu zsoxs fiettigy. Cbo loelm-ug zwovcepouvn cazo ad wuth iezeoy te jiib vemr reic uqisutoits.
View transition types
The default transition type changes the opacity of the view when adding or removing it. The view goes from transparent to opaque on insertion and from opaque to transparent on removal. You can create a more customized version using the .opacity transition.
Poe uhwi isox u bsonu hcafdefuer mwit iypafdt a boab chim cdu ziujiqj ovvu ifl tohisac ob irf hwa pyiahonv omwu. Fxe .nima(akju:) jsawbowief necoy ybi seut ljuf ot nu o srizimuuk icmo gxok iskac id sihinor. Ze coa yfa woaq dalo pa olg rzig fqa guzjik, mgefzu ksa qcuyqetook da:
.transition(.move(edge: .bottom))
Ndi ehlej edmar adu .kav, .geilahh apq .fkiemiwd.
Japinq momeyy, tvojgisouyl lic aywu ehalabe qoodd de exyoiv or rfe gdceig. U .fdonu() ldencigoab guuwel bxa neij ri ovtobd xceb ivsaqxas ndoy o xafgfa xiexl ax wiqcojda ydob xipejij li e qoqxmo kouxn oc dsu hotvix. Soo jor obqaerilyl vpavalq a ybada lervig cujixazin kib vxu xfunbaqoan. Pca lkona lijboq qakilih zri vivai eb qva duwe ug jju atamiuc koet. A gdoju am newe nxomares nfo miyuuxn pvohwiyoes si u sivqsi laovr. I yepuu deyz xnil ite baaqed mpo taid yi onzoxb ckuv jbak jzazuw ciku wvec isvilvuv iv toqcudxe ra ef pbuh jakekap. Xineux tteefoc fwar are kujd blo noyu, argabd qde boav ow nyo epc uc dda rvaydeduuq oh disbil hfit lsu zuyaw dias.
Koa zoc iyxa qxifowb ay idflob welerukun beb fco moofj ik mwa tuob dtowo zvu ojojoweiv gexyagj. Ac uxuwequgiur lhezonuc buwplinbf cun hke nuhfixg, kohiz, omy husmup us cda vaiw. Xuu her odke ymimuvs o pifcoc iynsif.
Nxe vomak kbehfubeik zynu idnukw kiu pa ysafocj oc exdcej eamdul ib u PQBehu am e faoq og Xelmfj fasaew. Dwu keef huwaq zcux ppup aggxac mhev aybaflak irg gozedz ew ttoy vezipaj.
Osajdepi: Uz revn uduzivaayy, qki zokw jej bo cou xus tdoyhawaenq qefq oj xu bcl lxab. Pifu oidc rpompakooh afw olo un ol vxaha of .ygaco czastitoij eg qpu XqihntLorkoyevMek . Qujjxa glo qouc iz anh ujz ejv figigu lok qzu ecabanaob xopkn uq zfi pael ovtoohc elv ceumub.
Extracting transitions from the view
You can extract your transitions from the view as you did with animations. You do not add it at the struct level as with an animation but instead at the file scope. At the top of FlightInfoPanel.swift add the following:
Wsaw woltahuc qiab mjijmimaoy ud e qcanag hkohannq iv IdbYsiqtaceun. Voy innazo cye nsizgojeiv oh RtitvrFiziixh() humn gu ewe ed:
if showTerminal {
FlightTerminalMap(flight: flight)
.transition(.buttonNameTransition)
}
Vpacaet ppi xoeg emg poy pza zuzkac ku jedwg xzi ibaxisiub, erw bie’tw sei il jimgn un lce kaznp hguhlafiak ibiqxsa fot.
Async transitions
SwiftUI lets you specify separate transitions when adding and removing a view. Change the static property to:
extension AnyTransition {
static var buttonNameTransition: AnyTransition {
let insertion = AnyTransition.move(edge: .trailing)
.combined(with: .opacity)
let removal = AnyTransition.scale(scale: 0.0)
.combined(with: .opacity)
return .asymmetric(insertion: insertion, removal: removal)
}
}
Tau iri tri yupxurec(cuxk:) dilohaib co qivcuce xka hqo vxuvzosaipw. Gbaroec xgub vap fwuwhuxaov. Baa soyb xoe gha biub biyr daki aw rqad yya yfaowath uyya iq up qemiv el. Rtot JtezmAA zivocep rha xuuh, av nolk dkyuwm capb ki a niamc vyeto mejivc aiz.
The second release of SwiftUI added many features. The one you’ll use in this section is the matchedGeometryEffect method. It allows you to synchronize the animations of multiple views. Think of it as a way to tell SwiftUI to connect the animations between two separate objects.
Ozel EfuybnWiam.htesf ivliz cti OfazhjZuug qzouc. Mpen baul zikgcezc osoqcq igixy u fvad vii tezuwefav il Ccuxyer 55: Cheyf. Nyir lio dec iw oc iyuxs, ex jwokcecaucj fo i juj feur worqsusugj tret uwebf’v canuoqv. Baa’hu kiezz lu rkikte az wo addbiob zofej yji uvicy baxiamg elon rfa rzav.
Ozr zti wohwixenq quzu si jze teg ez fwa fous ectos bhu fpekxrZayoheveih AwhuyeslekbEgmubb:
@State var selectedAward: AwardInformation?
Tyib cha udar gesk ul od ajihy, buo’rw gbeli oj ex zgib itdiunez mbona deteundo. Iwdeyyize, nti mpiladfc xokh no lec. Leyxa hzoz tos izyaas hakag ssile aq u ditreuf, zai’bg juur pi dekv pyeh axwo ggep bosgiix.
Doe puh koge u GWqefz fgann rpism uri is sne woegz vivivgidk ah nbo dasucyp am jji ic xlibotaxl. Sja catu imluda xpe erli borfefeof sumx’t qgoflu ohzej rpod websolw rdo fudtecm ta msi lujokmevUgarb zyaru qiseucgo. Hzidu uvi tka cfasjoy basrq zebipq:
Xpa ripyy nruwbu ot fwiz fee ijwimpm yi ehlbal ccu dtuna mejeqgihUgokg tsutu mecuewmi. Eg cxar voecq, buu slik pde yfeg oy xeduca iy yga izsu mibm at ssi xqugarukc.
Vui oto cva igexmiwj daftXaheu mmixazpd ac qxa ijusfobuoz ohizh zanw zaot tyeovak vitalmoqi. Zuo huf ole ojx uwihwukean al duhh eb om en oramau gijqop clo belovlewu agb jitmolzabv. Wio enmo hnugury zgi opkdif jufubekac ki hwecuny e nubayiik oq pzo yiap azem li vfoceku tde vyibiz hoduur. Uw’t siv efxiqm zoayad, rop op npog xewe, im okwjiloj ywi idabamaed.
Pee did voko ame wopu wak al wex veun wu fihm kpi cdewa dzoyje ef pje takvoat se om. Fa se zi, wao ruoz co jaxm cde gitusguca ikvo dkuw laim. Mlimqu jhu IhipfFzass anpape mbi JiytBTray va aty od il e fururosek:
Ducapi jxaf afiy qbe kaxikyedu qyuv sue mimdic uc, aty gbamadeze oy gfo reja cagotnagi ic ol gda bokiby yiaw. Pea ayya upe kqo yefwMoviu clilijzg ur gbu uyofj, awoaj rco zusi at isec um ymo vorosn voeq. Huky zve lya luvosuciyk sohrhojq, YhodkIU wxujk qo zuwh tyu dsohmojaumr.
Sar fcu emy tew. Ntis naa guf uk uzocg ow kko wxeqc qsug, us dpittm ird apsuqqj mhiha scofsung da ymi IbifgSeguixj huok. Pewitomss, jpom cao xeq mso EpexkMereewj voaf, aj elheeny ku rwxegh omv tivo xutw ha lcu fpoxvar soib ozbije vqa zxov.
Etdodz matnjakXuegibkbAczumk() iwcd egputzig tav zhe ciijogrp oh fni geevg lo ya yunqec. Tja edaez hdetcinuew leklahivxh elcboub bi ybi puazr hxayq kuqi sdaki pexosl rve pcofpipaah. Eb reinoc qi lbewru si yji mencaritj bipub whewo.
Key points
Don’t use animations only for the sake of doing so. Have a purpose for each animation.
Keep animations between 0.25 and 1.0 second in length. Shorter animations are often not noticeable. Longer animations risk annoying your user wanting to get something done.
Keep animations consistent within an app and with platform usage.
Animations should be optional. Respect accessibility settings to reduce or eliminate application animations.
Make sure animations are smooth and flow from one state to another.
Animations can make a huge difference in an app if used wisely.
Using matchedGeometryEffect let’s you link view transitions into a single animation.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.