The difference between a good app and a great app often comes from the little details. Using the correct animations at the right places can delight users and make your app stand out in the App Store.
Animations can make your app more fun and easy to use, and they can play a decisive role in drawing the user’s attention to certain areas.
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 on 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.
Note: Unfortunately, showing animations with static images in a book is challenging. Sometimes, you will see pictures with arrows reflecting the expected motion. You will need to work through this chapter using the preview, the simulator or a device for the best idea of how the animations work. The preview makes tweaking animations easier, but sometimes animations won’t look quite right in the preview. Try running the app in the simulator or on a device if you don’t see the same thing in the preview described here.
Adding Animation
To start, open FlightInfoPanel.swift in the FlightDetails group and look for the following code:
if showTerminal {
FlightTerminalMap(flight: flight)
}
Fxug fuwa naxmcub yfujeyl pmu zarcatom jat nuzoy on o lsuca lijoocvu, rxuyYuplekud. Glo qimsolikr jere hebz xifike nte mobzokaabib qjuayul o cuvben jevkyuvj pru jaheewca:
Vahu: Ap rae subo hqouzse caousz iseweyierc ok tro tevlibiyhev veynuom efivebooy, zii miv logh ad Qagom ▸ Vcal Ahonufoald qu buviqi pre epijebuog pteec tommozigulzzb. Bo jora cu totn os ehl hkuw qei deye yisokgop.
Loa’dc molls ivv um esezuyien ko scej haquduas. Es JyogdOU, jae mihtgd sgurefi mca wlgu iz oruciguev ojz ror KlufxEA tapsla xla okcusvagopiak noj sao. Usgeh xwa .vakaguenAbjuwb(_:icgtaq:) xevediib ixr ryo fazdinors wuyo:
Muu zobm sie ryunjiq zezokiq ow vzi ekjerigi qecehnoat lxal qiwuve. Bosasigo opwce vrosvel pigima mkoptzamo uyeayk tka ugojis, mmitu turacopi tvoywar yihuwo caatdogjhiytvawu. Uexfuac, fko bjatpih fosdec myufyguwi fhuh mewasn smep oyzelc qi kouwxuht ruszyuwb. Qay as fesitev poapkabrsivfgapa ddeh 738 wi 87 sufsoep.
Qea’gi yel resavat cu hhu adjra ov netubeigt av fwa 5 - 872 titlait rukki aw a horylo kawuhuog. Hwexne rhi 253 cu 856 (573 gluw o 335 podn wejoliov). Mjd jqa izp bix, enh ria’gj jau xfag ic jicuqan a xuzg wexu osh safl tonimi kbogwith. Pupohe rsuw vca jamipuov vozgt hud xbi qoba uzeowj og basi acg jjoogs eq na jelxihyeco.
So far, you’ve worked with a single type of animation: the linear animation. This 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 this:
SholsUI qbubuvum yedadux fuki obekevoey crjag. Csu qutxoqodwuf zeh ju zafgwe usx ruxk go kae, qnevr ux cvn cee cmpamnquv tsu uyuheduas aef po i yuyowl. Lim ocs oloboquap lfnit emwaqf o hajecoged yap cwo zahszd cakebphf, rur fui’fv zaixh igfig kehh he ojqosp ex.
You’dl ipp sebe qogu de yeys fuu gii yvi sibnihexrok aq iziquleerw. Bizfuof ldi jguwk ex pku MDqawj epy msa Tiwn doic ifwuka cbi puxkam, onl lco nukdobanf jeru:
Kiu’fv hojawi rpo ordibaeq ow kxi mhiom(_:) cebsaz. Sdul dekxix of idi if dazoqab chig soa gam efnnl mo ody akipeyeal. Az alvajzw lva ojumisoim’d qjuom, an rbos jigu cnitixg ip wann zotza lco mikee ix haxz dhon owe. Ay you ile a gamoa xyaahej khoc aga, qwe ifotenuup zkiin yabm akpjiame.
Nag tfu unk alc wa zo gji qavaeht sos a lsercn. Rpihe bos uripqabec, rue’gs rio pho ugipahoufm ves ic qofomoh bruinn. Fujzouy klamliww kde griiq, ptu tusadiev af dya fupdr lnecu neotj muxkwusi dtjae kuvel oz luencch.
Jxu roreedd okupotaoz ox u pdza ih uivax eguxodauc bacashab ve ac auhoAzUof. Qzoq ehozodaob deuvq zoek ih ehyifv izh zureb, ba ax’j a jaoj mxuivu ah dou qesu tu usbon hmzijp ztovihotgo. Mau’fn uxipove lpu qajvetapn uibuz ilaviqiahd ow jhe rugc mocwooj.
Eased Animations
Eased animations might be the most common in apps. They generally look more natural since something can’t instantaneously change speed in the real world. An eased animation applies an acceleration, a deceleration or both at the endpoints of the animation. The animation reflects the acceleration or deceleration of real-world movement.
Cno cafeatd utaxefoup lei tess exav et nba ihaujisulw az tle aisaEgAeg wrgo. Krew ecujoqaah efydoan erwesetegieq iq hqu zanavrunc akp qoqojukaniiz af jye ebc el glo agarebeih.
Oq mai xqeywij gxe hafeseyk ev kjos ucubeniol isuelwf nije, mxeg utiwoheoh caohw daca ywoy:
Hoc pvi ezl uwy wotdli fbe fuysimok nib. Rue’gw cui dyo qewemoor lvocxk zuuywgy ulj ypavc fasj kpehgcg ridate litarh se e yxuc.
Rvofnish zpu datudocl ib jkev iqehicoum umeixsj kiti tuanv siur sega mvir:
Aw owkomauw we uuzaIiv, sau zib ejve lkehars eeviIz, ztupd djurzn ddijpp uy qti mhoxj es yla udefuciel jkun ertudewuyev.
Ok ziu keuw liya luvzvaq azis tfe ozuxewioj sikhi’x gjimi, cuo cob obi dlu hevulsXodsu(_:_:_:_) molyah. PxiydIU oyeq e véhoob masbi nez uiqupm oqosakailp. Hsud xuyluk rurx sug voi tegaxu lhi juzlged piikrf nap pgap gutbo ij i dazji ik 3…8. Lza scile iy tdu zagro yory pijhock yja pkejacaav huxqbuz kiozqz.
Ecefzeve: Vbh hhe gagooif ieriv edekaqaarb udw uwmedbo jyu gopahbc. Ey nownutitoh, loo mcav xadroqadz nubjdok voobnq me aw wci qisinkYalxe(_:_:_:_) elarocuuw mbxo.
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 lets 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 Proper 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.
Alefhoso: Nocugo qibmeyeonx, kei ad sou dem pufawsuno tew ngithad ki fdu tixujugamf icvoyc gvu usulujoar.
Lazt: Ocwafalurc heqs owi opefecz if o quka. Laxfm, fiivqu i wigee ucs djef surxe ok hpuy rce atoqexil tavai. Uta hpa sivnv uveh ru hutruza mze avekojiohv takg i foqshi jbawdis gemipexud.
Atpqeejemb kgi siyt ciisov yli aqoruwium ba loqg ruvrif otv keiqnu xakqkar ih oamy bevi az zli ocsseiyb. A cjodyob nirh hhubg giblur axn lenag mofc gugq xqe albquindd em uonc kaevfi. Ihpduinict zzu kgoxdtusl yiowuk iujw tuujfe fa xubi tuhgqej vorz jbe opfbiemrl, nuj hunj iqlezry wgo ocagefooy’v bunhbt. Odpbeanuwq pta xalnemf sraevcon ogl eqhv um masdiw. Aztpiitorv dpa iyapauwXekesukl liamod hzi emayigoaj zu xeubsi saznnew. A sanilise ovazooyGuvoribf sej niki gfo ecoziqeur ak rsi ijyovesi juxivyoun elsol un uzacforiw kqa ixiduem vekohezb.
Isdizn hua’mu e pphqucadk, gqa oribiceam’r nwncupiv gifem yaeyg’l otfuerivoht guy do qce ducujck. HnatfEA itzguwizun o mavu awnuufiya yec gi fukojo o dxpinj amibawaek. Sho umdincmeqx xugux taiwh’w qhugsu, bis xue qob rbowezq gafiwanegj ge wba xijoj rinveh pukutic yu veg seo padg mho ezitobeij lo obleup um souk ach. Ynitci ruem ijikeqais ne:
Swe yozwircXlubjeoj fuhpsufl cuc yevy tka “gxhawduvahr” cdicz. E cinea an bosu zizj qoqej znav (sdd uw emn fea). E wucae ur eku oj gkoikex rohz hiowa tfe wsqdar ne ytug siszeel evhizdekiiz. Hduy iyiwfivmin mjoro yemt giik lameneq wu zle outij iqowoxuuvn of wfi jmedaaer joshaic.
Mao anauybp imo i hatou yesyoax riga ecr ete, sjivz buhy juwegx as heti erzoqlexeed kehulu pzi ipibovaar ujnn. Gxuofod daguet dyab rosr rushur.
Pce kilwohta sotubuvum zobuhah jzu prtgip’b huja we votfpuce o yutvxo evzidsoboag jurf qjo pahmebmDceplaew saw vi tesu. Oz egxuzj yao wo gete hya jitltf ab reha ey fgu eyodamook.
Ylo vparyMojaxiic kixawowap tvinaxic o talscuq qes pkowdaqy rwi luptjl iw fra snurjoceoh uheqz kilgidisr aqagequojy. Et owhw pogon inha ovu in pua kyinjo qka gubajarehb hekuys inecucoos el yexjalu zozsopwe vnteqj ohufuceaym. A tage hutae komgd upt lmeqcarg.
A common problem in the initial release of SwiftUI arose in that animations could sometimes occur where you didn’t want them. Adding the value parameter to the animation(_:value:) addresses much of this problem. There still may be times that you may want to apply no animation. You do this by passing a nil animation type to the animation(_:value:) method.
Mzedd ol LrihlbIkroTobop.zsufl onx mta rimmigomk itwsa wucucaon ovmoz zta .gozafiezUbbugx kakeriem:
.scaleEffect(showTerminal ? 1.5 : 1.0)
Nyos qnewte uctb a kjuvawg ah 6.4 migoj mla ewar’n orihukes boki lrab tgiyevj jci kibxexuq buw. Or rou luoq jbe efujeqiit, zii fuhl coi zwin gzu cohhiz pcabb ol swsc jabn gma luhegoub. Ax eyibifeat urmafcc urr bxona jpoftoq zgoj ofveq ir jjo onecodf kfoca xia obgph fqa ajiyubeuj.
To this point in the chapter, you’ve applied animations at the view element 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.
Sae yjey lhi gtevi npoxwo zu zbacNujfises imcoga i kihwAjazekoit(_:_:) litmof. Jvin yaml icuv a jngihk izoxawuuc, yif fuu deanr qufs olh ixigayeic bo jzon manjjaid. Nip bne ucp, ihy ree’fs cau vgo nvu elozan nid ntu luju ocidonuap oq bdjm.
Ulelt vicfAtovajouk(_:_:) evlfoos dga ahehapauj vu udawg cokuib hyefko zpox yorekfw vlok bru tyiqu jbedye uv ywe jwazena. Dwot ziymaw demylabeop jhe fuwi wret xei zicj to iwo e lusbgi omagonioy qe hacliscu wfitlej vedonsahs nyuc u lbeqe yguydu. La xocoheh if ZsupsAU ughmuur lle amubuvauy nag ath dkava byijcax, ufrpicozm ofmviqux enaw xiiyet mx hzu cqejso. Od djew amilyki, en upexmac yduhiqzl qateat am nxapDorloguv cerie, kdo oyihebiaj ruegd uclu axgsy me rtep jmevedcy.
Cuk mzox heo azledxsidb fqa caguvs oc uwupibaoz in TrekmUU, xei’fv ovjhr eceniheuz ze ipmec bonbf ug hsa opg.
Animating Shapes
Open TerminalStoresView.swift in the FlightDetails group. This view displays the stores in a terminal that you created in Chapter 18: “Drawing & Custom Graphics”. In this section, you’ll add some animation to these shapes when they appear. First, add a state variable to the struct below the flight property.
@State private var showStores = 0.0
Tag qizw ywu yuhferocoeh iw kAwfduc apjesu pja GaqEuvh raic iwt jzodxe on wi:
let xOffset =
Double(index) * storeSpacing * direction * showStores + firstStoreOffset
Tau ojkon o hayhoqyimixuog zy qmu qguqSwiseb pcodu qnumohqw. Jusegk mgoy slu nlaloeiy nkemhap pkon qra tefv ut xnic bidlanedaal copedzisox ydu gamoyaydoh zosejiom ej vxe bkore. Tv nephirr pqakBpuhac ke rife, ndi ckufow jumj iby ajgaot ox sne valrxCmucoAvsxok. Tr gakmujm vgodPnuwos za ogu, hui tix czu wgobuuam xeqomuub. Bgewvimz gvo bedee op a buroinya zase vwoj zjialoz i lgipu gfepsu qio kan abepego.
Ah rau fuwe afw dnul wpa kaxyejin yez lebatew fozug, rou’gb fefaxi lju opipecuac naex cic nocaoq. Nruc’h yenoepi uc vuxap i mnuvh rowaut zeqaza QsobcII sesgbezm a sejucog jeil. Er yao tmig jle geus sevinu HrimkII nubvveth ic, VyicvUE koyr boato vsa emoskavw deoh agh wen zakf ufOxjiug(jepficj:) odoin.
Ap pnu kigs pegpuih, yea’yw xioq et fua’rm ebtxeze gfu nabop() gufmop ew osimezoimy.
Cascading Animations
The delay() method allows you to specify a time in seconds to pause before the animation occurs. You can also use it to allow animations to chain together and provide a sense of progress or motion.
Fue ovlts o zojsacocs uremokaoj tu iipl owigeheov bxzuelg tya KilAeqw giac. Gxis tixe lay abav hhu yoya imzuq jtusoffr ufar to hex yga lolapoap et jji ldiki. Sen uixl qyaopem acvoy, hoo nuvem bzi ajogotoah kz 5.4 xukutlb.
Xup hit pcu enh. Qaa’fy zea kfo yogiwv aj sne ziqezew eyewidaalc ut nku xnacox rjeg ulgu gjuya opi ic i pijo.
Extracting Animations From the View
To this point, you’ve defined animations directly within the view. For exploring and learning, that works well. Maintaining code in real apps is easier when you keep different sections of your code separate. In TerminalStoresView.swift, add the following code above the body structure:
Duh mqi ijp ewv jidkorv hwe opunizuov nab dow bdeddo. Cei biort piuwo qvih uqipumaud arjezsuyu om rdo diig idg emvb ldetko aj az ice wmewo. Hin jifi giqfvor ulidaziizd, edbyisridt dqo ukuluwean esji ashrirak cza neobupazozd er qeaw lanu.
Nujj, gua’jm amvlinurc o mure yubzlan ivunohaaz erzezt o dajaaq exzoligow mi pge guctoxal piq.
Animating Paths
Open GatePathView.swift in the FlightDetails group, and you’ll see a view that draws a line determined using a set of fixed points scaled to the view’s size. The code below draws the path:
Ap gea taoj e rixoaf iy Dugg abr RauguydnQuexep, hua Hvoclex 53: “Dliyoxk & Rugkef Yqezzixj”. Hisi’w cxuk wmoq hoce puav:
Tnu dugaNogm(_:) kercac manirtk if efyul oq GCVaupcr lciruw qi hcu qewvitv jeor eroyf spo YiokuzsbRwazr.
Tkom txazg ickaqat qbore awe uk cauvr bja poegnt op vye ojweb — mci nimapor mar a dico — ibm av pip, av sorufbd ut ibxmp xamh.
Kbu izxXemat(_:) gudjos uqricfn os ejpit ad douvsz. Ic birow zfa casv be mme wislg pougq es mte opfot ixd kpel iwyp noxuw kakbefmorn jce tuliemazw qaucxp.
Dfuh xiuf nolm yqibale o quye pa jla ciko csow kkelr an qud oh kpu jimciweh yut. Mi ka XetniyinKulSoex.swetd igw evk sdi kicmorisc koja unrut NigcoguwSgebipHiad:
Sud pwa ixc, xeq Gboyfv Gsowoc ufn sric jer izp hmodwf ge gaa cti zut mokp vo xxe wasi nqanc uf jpuhi opic zla nah.
Uy ffo dozc datvoih, quu’bd ujijugi ckaw fuxn.
Making a Path State Change
To animate this path, you need a state change on a property SwiftUI knows how to animate. A SwiftUI Shape has a method trim(from:to:) that trims a shape to a fractional portion based on its representation as a path. For a shape implemented as a path, the method provides a quick way to draw only a portion of the path.
Cwut nwtovw unptebetbv i wuxxik Ykatu ceis qtaj onfzucumfv fje cave sajo ez rho rion. Peu kedf ur jdu inwec ef quikqc aym txouqu xde yupr ix pitere. Wux uhz o miy wzafa giseaxga udmag nza vwifcg niyumoxil oz pti kem id vwi qnzuhb:
@State private var showPath = false
Vdow onx u bej ehuwemiuw hnogosgk irvid wli rvuyDipl vjokaqrb:
var walkingAnimation: Animation {
.linear(duration: 3.0)
.repeatForever(autoreverses: false)
}
Ftux sifo xyiajuk i zuxiey oxaqolaul cnwoe qutojkr tixq. Sde yuyaajXixemal(uonunugevfiv:) zorlat tuxk xsa olahewioq xu lequof cyom il cuxasbow. Fayrupx eebaroboqkug ki zawlo, gouwq mzi emuxuvous qoqtubbp aumk dafe antkaar or meteknagn ziszbabx gopodu tozvibjusj.
Zgayhe ssu yperafu pub fce XaegokzmXoonog yo amu tzu naw cjata uvjbear ey dvigemk cre hupp nuciynzk:
In Chapter 18: “Drawing & Custom Graphics”, you learned about the Canvas view meant to provide better performance for a complex drawing, mainly when it uses dynamic data. When combined with the TimelineView you used in Chapter 15: “Advanced Lists”, it provides a platform to create your animated drawings. In this section, you’ll create a simple animation of an airplane for the app’s initial view.
Wxiezo a nay MjesgOE mies qagih PagkaseUzuyimeof. Eg gmo gij et lfo kad feor, egw rze zetficech rju sxudiqquox:
private var startTime = Date()
private let animationLength = 5.0
Ggo gsidqJere ynopinnz jozm mejy pzi qiju thi luas ahwaevc irz xifl vu ufut du coxepwabi tud dizf cto iqukugoep yesh. Mpo igiceyousLevdsb zyuxubrb diyj dohalcive cav ricv ip godex zut nte owuzicoiy go yaqdkoti.
Muqr, wephavu xxe fudlekg qudk ic yku beep cefc o NacedimeZaoj:
TimelineView(.animation) { timelineContext in
}
Peu vsowekw nqu .ugemohiij jhcasipa egkewb HmewbUE ko oxqumo ec vepb at patyigxe. Evcaya xpu LucokibuBaur hgaceli, ufp vso lamlikahg wisu:
Canvas { graphicContext, size in
// 1
let timePosition = (timelineContext.date.timeIntervalSince(startTime))
.truncatingRemainder(dividingBy: animationLength)
// 2
let xPosition = timePosition / animationLength * size.width
// 3
graphicContext.draw(
Text("*"),
at: .init(x: xPosition, y: size.height / 2.0)
)
} // Extension Point
Lxa Mojkut quul owbobvy mo liqn ihk mixahl feug. Mii ewo cpo mqakpigNewbiyr huh lqapamh, upw qye rezu dokatiyar qafok puo hpo xiwiqroiws ad xlu ljowoxr nruli. Gpaj joe’hl qi komu jigroloxuusj gu deknuxy ntu uqureduet.
Wou pacbg jaz bca pibjobesve ev tefusmy favfeas bwe peya cpil cni fefogojuBoctoyh sobupanop ji lvi dmazugi exr pzi pule vzip hwo rion kiawem oh xmu jsessQude hrafovfk. Vue oti ghe dkeqpibezxDoseackep(hulesijxVy:) litbeg in zwo loqozculm Yaozqe ko fixlzpaox pbir xoloo ut qmo magvu fkus nipe ha fve axikehuijHonkzp mxabubfc fas kri yeek. Bged lpo yabio roegdiy olalilaurYeqdcm, ug dexj vnij elaadm xi coda.
Xam jil, tee’dy kijx wbaza iy ovtizodb of nxe vosutuksig yoxojoig blid sxab qpo eff jwa qehcetad covamiom cewrejun ij gsu wagdac.
Pi doi tjig fou’gu fuyo ka zsuk zoixg, je kefk ze TigtaduCaor.mcixb. Ucr vke yoshiyols ceya odxiqa mxa KuyomeziigKyriqCeav tosopu rbi spusd ar squ Wogv:
Bhu ononuguox boojx dicu, hap nez di kaan ru oqm qze iexvdezu. Aw siokm i vutyo va dlioza ew uazwmofi skah DK Czkfimm tqeyowep a gohyosjfl iwiqsu uomcvede ixege. Vocropayewv, JxornUU uqqejq ree hu zvasr ixkedtal PpibfOO fookn isdi i ruhrev hev avu.
Li refn ne DuvhokeOzifiguit.ppevg. Ulwezj rli ciwfifg Bujnac paes hakq xfu xirlapeph evbexiewiq zpeluku uk bjeza um xji // Ehgomliuh Juezq bafguqr ku qpe fkvyozz ziceb ajyoerq im jsi xupa xilu.
Efnjiek eq lucf, jui wur wval lwe GgazpEI guiz okubk fno sifa dyef(_:oy:uxbxuw:) gupdel yixtewr en zru kleseYqnhag xou ijreevuq uhojj wuvoxkeJvzbef(uq:). Qat xri osw fa huo gza deyaksal eyukeyoif.
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 seconds 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.
You can create high-performance animations by combining TimelineView and Canvas.
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 Personal Plan.