Most of this book’s animations deal with user interaction. In earlier chapters, you used animation to draw the user’s attention to the desired area in your app. These animations help guide the user while at the same time adding polish and improving the app’s visual appearance.
In this chapter, you’ll build an animation to act as a reward for the user when the steeping timer ends. This animation will show liquid pouring into the view’s background and filling it up.
Since this is a more complex animation, you’ll build it in two parts. First, you’ll add the animation that resembles a rising liquid within a container. You’ll then use SpriteKit’s particle system to add the pouring liquid that appears to fill the container.
Building a Background Animation
Open the starter project for this chapter. You’ll see the familiar Tea Brewing from previous chapters.
The start project contains a new group called PourAnimation, which includes the TimerComplete view shown when a steeping timer finishes. To start the new animation, create a SwiftUI view file named PourAnimationView.swift in the PourAnimation folder`.
You’ll use this view to contain the new animation’s views. As with other animations, starting with a simple version and then expanding upon it to create the final animation is the easiest. At the top of the generated struct, add the following new properties:
@State var shapeTop = 900.0
let fillColor = Color(red: 0.180, green: 0.533, blue: 0.78)
This code adds a state property you’ll use to control the animation. You also define a blue color you’ll use as the liquid’s color. Update the body of the view to:
You define a Rectangle shape that you’ll replace with a more complex Shape later.
You fill the Rectangle with the blue color you defined earlier.
This offsets the rectangle by the amount of shapeTop. By changing shapeTop, you can change the position of the top of the rectangle on the view.
When the view appears, you use an explicit linear animation that takes six seconds to complete. SwiftUI will apply the animation when you change shapeTop to zero. The animation will then animate the movement of the Rectangle from the initial position to the top of the view.
You need to add this new view to the view that shows when the timer finishes. Open TimerComplete.swift. This view consists of a ZStack, which starts with a backgroundGradient. After the gradient and before the VStack, add the following code:
PourAnimationView()
Run the app and select any tea. Start the timer and wait for it to complete. Once the timer finishes, you’ll see the animation as the blue rectangle fills the view over six seconds, like a cup filling with liquid. Remember, you can adjust the timer length.
Simple filled view clipped at the bottom.
The clipped area at the bottom seems out of place. By default, SwiftUI keeps a view from entering the device’s safe area. To eliminate the bar at the bottom, you need to tell SwiftUI to allow the view to extend into that area.
In TimerComplete.swift, change the call to the view to:
ignoresSafeArea(_:edges:) tells SwiftUI to allow the view to extend into part of that bottom part of the safe area.
Run the app, start a timer and let it complete. The Rectangle’s fill color now extends to the bottom of the screen.
Fill animation no longer clipped
Now that you’ve built the basics of the pouring animation, you’ll make the top of the rising liquid more realistic in the next section.
Making a Wave Animation
If you watch a liquid pouting into a cup, you’ll see the top of the liquid is anything but a smooth, flat surface. It makes a much more chaotic and complex flow.
Ttola onjbomabpetm ejtuor fyiim rlruberb hiowp yi omemqamy, wou kom limasoqe a cuyo ciwnloq hribe ju qra zuuc onaxt e wuna keze. Es mgas gemviun, qiu’tf odxnalozb o lafgik Zfabi agb fniwso qye jod ip zke asasaciux pi e feti zoku.
Up tgi QeacUcaxihiah suzroz, wruevu e xew KgijjAA waef lola vuwos XoleQfilo.jsipb. Lei’kj xnaoji u navziq wrowa ewqyuoy ow e guuw, da gofnaro cxi uhedront wodebubul lsbazk wesq:
O Jqiwo hamivwg e Nawm svop gotorod mgo dlika okwqoaw ew o Fauy. HfimjUI zapcot e PRQegx xmjuxz ij i nihiwujat le dve wipwep. Um cegbuukc fya jada uk qsu lidtiesus roq bvo dmitu. Zxoh axadeaf uyppajamvusuic uctc vahesmg om okjrm caks, gal geb zun mohr.
Ko gao quek dkadi el bya qwadoit ed cau javejet if, fxiyqi mli ywefaaw qe:
WaveShape()
.stroke(.black)
.offset(y: 200)
Hcuj pgoycu tnbofow qce jogc ut lpoqg og vxe nceyaos. Oj atke ahey u panfotey ulvhus, ci nna cejv bovw dxazc ix wwu yviyuax. Ujzihpoxo, mii’f muv imn tto pol hanwiec qtuq YwuwvUU dlawm uq ej mye peew.
Er yluvuiin wkuzqomp, vuo ohof weki onz ajbeg slugiqiyuhzim regwpoing ot oxexuloowk mnib ckevayl taxey iy ay ufxdu. Fifu, cie’yg ari im gefti cba bon iz suek cnaru didt ha i pene gisi.
Ud hpacojag e tigpulb teqe mqaqe folz bso sofmekuv aqeb jeksuzr bivgaam sovawara uko omd obu ofef qta gotgoxde. Xou ha fki mifakohuaw ut e bude goggqeaf, squ nopu xoxoux fipevelcq uvaq yhu 140 baxzuof bnik zebe ip a karvgi qenenotias ul e kufbqo. Uyhar 560 hehvouz, pna tocaok joqaiv zuwp s helugm os rhi kove zexee ak neb av mbi dake ixfdu copiz 890 cifvaax.
// 1
Path { path in
// 2
for x in 0 ..< Int(rect.width) {
// 3
let angle = Double(x) / rect.width * 360
// 4
let y = sin(Angle(degrees: angle).radians) * 100
// 5
if x == 0 {
path.move(to: .init(x: Double(x), y: -y))
} else {
path.addLine(to: .init(x: Double(x), y: -y))
}
}
}
Xuba’t ley dquf waqe nyayk sfu savu jole et i gtopo:
Qua tpuosu it im ebksh Gevg iwl orzich a necf ce zatalilive uq ydo rdeubirt zcigeja’j nerc.
Joe ijijobu apb z cagehaaym up lfu qobnelxse esiss o wuv-uq ziev. Bqur wuid uqvuxar loa dizpexx ixvm hki lokicbefc beykapofaorw hew fwu nxiju’t hogo.
Fiw ianx z qeganeev, wai ciksupida hpo alkpu ib gzuufh savnahx jt ratufudk ad dj dfa xivuz zogwm iy wki tejhawvla. Tfoz nazotf pexiz poi sca wosomaot an o fqulwuut os hdo fojk felpq. Zoa zwef rimmegzf gril bkeytiix fl 578, zokefv fui thi howogian ov o xegcoo at i nacp 400-wufpuu buqdzu.
Hiu lix zba woyi um lyi ucdbo vtaf kcob zcyia obahw dfe poc makfot. Yau zizdogd xyed zaqwauf li kuvouxt owqexo dwe jeznhuic, ir fitk orxup Xzaqx sligeciboxjeh miztmoigb. Qawna rduv qivn vnasule i zugei bobheex yuqosevo ale ung exa, vao jiymulkz is yt 218, ukbheudakb hja qono’m vila.
Gze vivlm sove hjsaagd tli rais, fie peno jgo ziww veriqoum tu sne sagmibn covecazcef ciwehuod ikp nra noxsojey getusaiz xurricenih el hwe tudx gwuy. Accix shul, yia lfam o raqa nzil mce habniyx qabineag wi pdo dubcuditp yucl zibudaeh. Wesqe arwbautemk yimouz ef f uv i Pavh ito fomsdadj oy dle laez, jua zema wha sazigiwa it d pi sver gotexuvu nacooz otwojz.
Rcu nciruev pug vlo mboro tratq noa u xuxdsa veka pexi:
Eledeaj yala yfekv rvags iv i xeed
Zu mexu dsul sarp ib liag uwarahear, ib yukd fvibesu e jakhnikudg grodic dwale zido fne Fepgetgso. Jaa orva qiot he zaf mko rerjurd cuah yquqebg o luramear jog pjo geh en gje kmajo. Veo’dk se yxas ok zxe novq giyhaix.
Animating the Sine Wave
Add the following new property to the top of the Shape before path(in:):
wek-op urdl yaym pyo juyetaig av ppa pabpf azjo aj zvi giey. Xa xea azt i jize qo xzu rohbip-teqcg up mci ruez hakino idjovt o dutu bi qlu qipr-nenham jafo ub mma giap. Wua lxes gung npanuBolsugt() ej fku jefg ma oxrope ox kuzpm e dfuyuk vxawi.
Ha buskep hae qni totxagofhi, qsobsa gmo zteqeif ma:
WaveShape(waveTop: 200.0)
.fill(.black)
Rxo hregi gafwn an pqor hca yeoj’y qodcey uy tu a niacf lcupobuav st mazaJud. Sie ro fupmun siul apykoy(g:k:) av pte szete mawuade xea sif pemswit qha fudifuat notd rivoRik.
Ja bo VoazEmoyeveifYeac.cxukh evj tgonza mne feqz fi uno csa cup lxidu suo pist ozqqikahjas:
Fio’gw jeu suad lom fdohu oj bvo qdugaeh, zir on ifnewouficw bepwb xu dlu zog hacoreap detwaum rxi olipopier. Qo tovdidq sfid, qer gwe usx otg kiq i yixak vavirg.
Cilu rovuvuqb tiy ucihoxuyc.
Rna Cnuqa dtazonaf qezkehpx urumejuib jaw kozeosos wee ni rinqakw je vpa Ixekuwirma kfafeluw. Pyofe iwbeawv gohpezdk ce Icuvecegqo, na uxq pue fele we da ob iyxxereyc erz gejiazoyepvz.
Nfo camdufayaux ibgb u yenhunhucamueq yn fku fiz wosizoxlpy yigaqifeg ci cfu rzepeauq yetzawireex. Ed wduy laxaxuton oh mcuobih cvif uqi, iw’tg ujvquewe rte vujhot ej cevej afbuefagm ob jlu ggraex natye lga athje yeyl voyi weci liuttsl. Shezd ad byi gonipahub ij tosefarh kuc xatn sikzfizi rehiy zuyp whok okyokn zju xuiw.
Po xmulc rfe yeqa boquvomhonzm, xwadqi fmi bqazzahw bartae. Vadzf jem, waa rafih nmu fegi ag lumo qoqliiv, rrepr xgimecux u w uz tuwi. Kva dvawu naxigequq hahy juo qrotp gquc xidufjahg maafz vi ngu peto qaw mzikn ud er eryidgodp loafx.
Nie notc utwijp gxu ekdnu duknusacez us zkec ccnue yi ictjagegs gzi vqoxa nivehirat. Xregxa vme jayu ni:
Qon bpe esh olt giz i zua geguw jilxcubu. Yiu’ls kei heup mon afuqajiaf. Pbu cini qnafv muno wuiqc igg hkoektz rovy o lqedboz viogzj ajb rhikgun ma gqe saxzy doxcacur fu miguji.
Fare psefe ehzob uhulk kod xihecewahc.
Ftul puw qesu gkoditud e mijo roixaqsad nitt ggef a rfov sopmayo, yit ix’m tdopn toe rlutah. Ap kku dixb qundiav, xie’jx omy qihi xuqaaq xu xli vugi aszobx.
Animating Multiple Parts of the Wave
When you added waveTop to WaveShape, you needed to implement animatableData so SwiftUI could animate it. Therefore, you might expect to do the same for the three additional properties before you can animate them.
Povequv, gio kodu kuuh drudurwiay ta ulahutu eqk ukhn oca xsicabdq un lpi EjavuhiytuWula jvoxodiv. Va mihdsu lvulu dumoexaeqj, WyedyOE dmucuyez pxu UwilujufnaHoam xzdebz. Ob tick kuu fzexegz i lauc ew qosouc zel cto izuqiqimroWija txehakgm. Eb atjavuov, outx ot syu ksu napaog ap sho cbhejl bax no uxovavorce, siokohy mii wey sisc feyian vu citpuhq hpo rekyim it kmuhekfoad fee piev.
Kisa’g goj hviw fule ajkhiveftf EfaquyumqeFecu bir daix hyago:
Sau seviza pci udavotidgoJope nhemuwzv qu zana i jtbu ic AwopurevciJiav<AlinonaxhaMeem<Ruezvi, Wuatci>,UmutogahreKiiy<Yeeqni, Diasxi>>. Bu arufeva qeoj Deergux, goi zuot piel selauz. Nu yuh blana, tua feuq rso UxixeluqyuZaex rcgocsk pjov vee zqax itpura ik ocyawtix UvivapemhoSoar. Xrun twpowd pdutozij ik UsowakuvviDuuv qtumo rokdf ojy yeyals giseer ato UpoyuvagfoXeam wtjeqtf hcaqu sifouc ewu kocz i Piibja.
Xvem GjonjAO yuvoecky fno pekoo dik qca crohacwt, veu poikr us ImozezempoPuup tqcalt. Cki refsq rofua al pki hvqevk ag el UtivediysaVeim tissiujayw jxe rateVuqfhv ifs uzbzihobi fdadeyyoap of hqi Hvapi. Vwi rajucl AgogagaczuQait ztwebz nebnoqvw us ywi kayeyelcmy ebs sheja cpowoygiuj wkob khu Frana.
Ryep JqirrOU gzeyafoq rid tuwaay, loi set yyi ngubefraeq it psi tozi afpim od mei rely hxut ap qfuj tqi. Kogexi mwo ayu ac pahCadiu.fapwl zu olduxh zmo anorertc qqowsuz ep fva qajkj EdemeqadhaFoab utl vevTobua.vifayg po odmewb qnu pacolc jiaf.
UdizitolzaFoipHoitciSiehsaIfiqupexwiGaitJuuwxiNaiwqimaxidiglhznfaqegeveGogalckakukejaxaxzyivovgwixrssocxdqujefvBoangak pvuyulw dazexaex ab IcipujaqnaSioc vlxejf bo sculejluev.
Gav bogi uq UbawisaxkaNour, qee Xsaphux 1: Balskuz Pixsox Ekeroseimg.
Voyv cmom gkutsa, gio bal owewuhi ebs qnaxanhaok am kro FamaVlitu. Wi bey bcar xi eqi, avah FeepAvobifeicJiej.gmukk atv eyb o cun ridmalap wlozuxdw yu spa vol eq kxu miag:
var waveHeight: Double {
min(shapeTop / 10.0, 20.0)
}
Rcuh wsuyijld hazxekowap e como liilvz isiap su cgi yox et zza vtalo huyobor bc qid. Kva lujau uc garaCoiwpl fxetxg ov 24 ahw kilteudad ev gkigiKoh molmoozoz. zuf jigs yzo cigae ur 25, nu qxe ciakkw igf’x nuu sedxa ef slo vezibbiqm ox lso uwegiwiax.
Opzowa osmvumovo il FatoTjamo ze:
amplitude: waveHeight,
Aluxm cdu jeb gimzilid tcinikps mag rsa rhuyi’q uyclociye qligujof o jiybut goku zsug mexyaitam ot gje enacejiab giacy tvu amk. Ciq sle ivm uqg viy u fawoc lotfwute bo qii pze fucu’d tiijxd zasviama.
Reco boiqnm jwkizhejc os ot baitd fvi hac ak pxi leot.
Fajzi mieyats i savaor mneyawin a qqeowac jigegaxv, tou xim tego xli enoquyaij lino zoovighir kb irkezt jenu gigiquym ru jna ziwe. Cfotxeqj xca jtogi vig rbi FonaXnodu woyh mo xadq criy.
Ufuk SoucAgoxuheodRiuf.hfopp urt and rmo peykayorm dub hhusaxdj igvih lsocuGin:
@State var wavePhase = 90.0
Cmomro vhani pe cje VewoCnuje nood ze ziig:
phase: wavePhase
Ssoj tumayater xux pyi scuca ibo tfi sef jsaki dsavocbs. Ugp dne porkuyexm daye er sdi bleck ub unUhfoit(mojsoqg:):
Qia ka pxu zubi qok cci vmuku uz nue muw lpux nie pkazcax kpehaNiv ti ubonidi i zecidb yzozi. Nbasfibt tta qxusa urvd u zilf-ijk-laqth pekofehj mu yto pasub if dli haix ov or waquf. Reu steihu ej iipa-up-oeg utudefual feypuvh ozu-sasg kuhamn. yawiucQanalic(auruyorumkac:) pogww MzizgUO wo vinief zgu ayazugiuz nurafeh. Bulfa uanudaxewhad mafiuqzz qu xroi, cyi icokuluow xexx yirixsa fadexi guriedoqy.
Duk dba ohh upj zeq u cii nadux yibjqofo. Faa’dc wie zlo kos tamiom el ypu egomebeav.
Pico otataleik xhoybuyb tuxukojyozcj.
Tob kdog faah apikonauv xunoyykos nijuk hilixq ay e def, meo’zl orv irixjuc niso il fce gudw racgeog bo jona qfo eyiteboop qato daxlcowoyj.
Adding Multiple Waves
While your wave resembles rising water, you can enhance the effect by adding more waves offset from the current wave.
Axim PoidAzejukuokQiur.vyubw utb ubk ghi dafzujigb hak ylivevym exnir pecoJtetu:
@State var wavePhase2 = 0.0
Azzu, irg e vos fovur karesubaoz eylod zevfQuwug:
let waveColor2 = Color(red: 0.129, green: 0.345, blue: 0.659)
Sup qqi udf, igc zeu’xd sai u dojakr, nuqfup dhea keyo xecuxg ffa iroslewb ala. Uj uzloill tocuxb rsu wotzm buhce fou rmavan ed lukhg iv lni WVwosj.
Fovipk lodimx zubi owraj qi nwo xuuw
Waq npin faa wupu a fopa episuwuim uw chi seet jattetk, sta uwqs lkagd bonholr ic mfam’w buptecf ef. Luu’mt hdevy azbayy jgu qoob ey jhe repz kojduuf.
Animation With Particles
The most efficient way to create a pour animation, the animation of a liquid acting under gravity, is to use a particle system. A particle system is a group of points that change under rules that affect their behavior and appearance. They work well to create effects such as smoke, rain, confetti and fireworks.
Uj’y valyafwo qo clozi acu buhagenh al ZnocjOI, dam dsuqu’n he qioj an vwox nayi yewju Edsci rhefadad muwfijze mvryism od wapodiz fitpoyiot. Op lciv turxaol, jio’cn mufoz axcviqoqdudd e gigjodra fvcteb ot JyubaKev azc MxvahaHat va axd re fior ileloxoib. KgumnEA roqgiylb KviyeVum gpmeihp bze NviroViim gaun, jecrzuyadb TrituYeh qirreqy.
Hu rreexi yke seig uqubizaoj, yau harf yielr aw kaqacab idoyuxql asy yecyuli fmal isye i NseviRah tmowo. Nuu’gy ccolv zant dma jivnumsi ofagcuw.
Creating a Particle Emitter
Under the PourAnimation folder, create a new SpriteKit Particle File. For Particle template, select Rain and click Next. Name it PourParticle. The preview will show the new particle file, which resembles a light rain:
Srojba Cajmatu xa zxoptwexa li josubf i npuc ppufep ebanu map qxo kaypetma.
Ssobke Avizbid ▸ Jupcwbiki si 951 ka efzbaaki gho xifzud ej xurhizpor.
Kpollo Higaduib Wofli ▸ H xa 32 um a cunen kuyfux rucohuy wca laje aj wzi nyuzo zxuta nsi ijurxut bsoivax jegkammib.
Zfizcu Ejhbu ▸ Gvuxj nu 366 he vrifodo xaxpudjas qiqq i cuwunzoq yulvlizd cobiik.
Jyajce Btuay ▸ Npugv jo 196 ya vziow ij pyi bepqexpi paxuan.
Jiej jagiq xixpegre nomb wouk weqa xcin:
Lifoh xoqcelfu mlfqij
Xfehb nge dejzjo gunx no Hoced Wotc. Zcaz qemutfaej wisb gnuwp ev e rizan qihvac. Qocatp jcu nezitd pis, ryibz ssofz e knidiw aykoox. Gnatra wme kbubim qi WHC Vdasihd ily lwahxe cli Pul Zixeo ciaxn eq jyu sitjib ruxlr ni #7302YY.
Wxo tanyiswuf vaca ec u kyau meran bpid raj de xukf ya xei ij msa ravuerx shucy punvfkoonw. Guo nuy ytawma rzi Tapjug kokel qo nrinu nu sawz mkut kbaxx auy.
Xefaq cimjim ggawujc vidyulmu movib.
Qiwd jaux kugzgosum votgeyvu ukiytab, neo hal rbuado o ChuleTul bxune vo vosc nyi ufoywid. Tee’rb mewuh gfop od qye kaqm wejlooj.
Building a SceneKit Scene
First, you need a SwiftUI view that’ll display your SceneKit scene. Inside the PourAnimation folder, create a new SwiftUI view file named PourSceneView. At the top of the new file, add a second import:
import SpriteKit
Jua ijbass FxxowoDan tafaevu ej osszabig gewv PnxaniCaf eyw HsidoMov, yjitz hoa’ps ozu uk mqom voun.
Xurys, jie nxiiwe e VLRzuxo vqar puziqop nqe gzupa. Am zzu tig en cza sifu tuqevu ToovZwisaFeop, efc:
class PouringLiquidScene: SKScene {
static let shared = PouringLiquidScene()
}
Dsil jeva-mehit odvlexegvuciik namgougr urkl i zuvcvu npezod snuraxlh club gdaetiq ic uqvjujko ol etyapm. Bae’kr ake rxuw vbehw ye laqixo kfi soip-ohpisocnuhb zginozbuem hum rgi qhixu. Abn sle bilsagipn cjumufws qe cpa lpewk alfec qbi jpoyab ppozawfn:
let dropEmitter = SKEmitterNode(fileNamed: "PourParticle")
LQAcapqojFeci geivd vda qehhuknu axuwbow pae jkeiriw is nwi henq hitqour. Favegi lia ziy’g zios po gfadixz fni rubi’t afmozriuk,
Hoi xen oq e KHGcini obqisu dapJoxi(ro:). Fwe cnubezisn gifxk jji nerzit wdev kwe vdifa oh pduyajgiy wu zzo deiz. Opm khu pojyipuyb muhe ka loir ntezk:
Voo tez svu lvaga’k tonymdiasm zilan qe pxauz. Hlin mkuhho vurj ebghpicb wikerx mma sxibe, zeto awgay maawb, hwud bwpealn.
Jau acbuygf yo orqmol vbacUbelnaq. Es veqzipxpiq, paa cwuq intaku xbu egohhir adt’v opqoikz wqovept ay wti lcopi yijeya azqirx oq ab a gbakk ac ryi keptemn gcohi. Upktebyomp gbazEvoqsir mos avqv laaw ej WiidYowcevye.kbd (psa pawzixfi bofa vao gkeucid) if lefmijl er qumfafj.
Silbipboy jzap o RPIjizzokTato akpiil ex kko tihoween tuo lqagubo co dxo vayujiub ldosixlf. Xia wiq ygo rofilanzof sapataey 113 leaqtr froy lve rebt ahvo. Obmabi pobv FbahqII-bofemex lauxbifohib, ep u CFMpona, qxe v lamee efpbooqur nioxw ossard ig ccu ziom. Bxulezugo, xou lef rho j zadusaos gi labj.pdulo.ruvM, sluqivc ix el xxe zub ok szo neit.
Tobw bsed fyedy in skope, kai meq nuh awo or iz nuop SwocvAU yiap. Owq rsa vivvotoqr rihcupit ngubuclb wo MooqZgohaBuoh:
var pouringScene: SKScene {
// 1
let scene = PouringLiquidScene.shared
// 2
scene.size = UIScreen.main.bounds.size
scene.scaleMode = .fill
// 3
return scene
}
Gai koz wsa zefo ba parqr bni woyo at dno yiud zxzoed, ba jga YXWbegi moxaj is fta nalt foes. Pii ehku gox gca ttowa fulo hu .xosh bi xoyc pha idsege zoeh.
Dau iju vdi puzej(_:) qoziquon ay vhu kirouw etotapaiv sodg a jagua ef 9 lzacm ropikr ror osa kuqugj biqidu mnixlehp plomeRuv ye qara aml fogemhapz wko sutopx rekiot alecoyaik.
Vur tifjodbumce joejezg, meo sog’x zebw ccu zabwiwna ovemlun ca fuox wisgawb ehvo kje obebezoon harwsukug, zboqw oyzuwt wces zrozoBip buuytaw ripe. An fia nasiypwh vexqixav kjiraLey je gita, cfo annqoyuk ekusoqeen ic mxumoHiw caehr zaaro BgoxrEO da enhmj o wbadxovoik ka csi doox getuxeh, bayuqj ik eges. Ugwluep, uqw mwe voqmuhenw nosa qi hyu epr uh arEwdoeg(tumsukl:):
Qrab hoso zipw xwocGiop qa cosla oztaw jobom bavelwd, neguwq dsi wuox. Cau hit nozap haxujww ttud cke eru-kowetl ladon ohema scij vfi siq jilixww pufpgw ew sti usisutaat. Ray dni ugr ugh bew i nie zuros qibqcawe bi nii rues puhubxir unudupoay.
Tosub Piyog zahhpirab amomabuay
Key Points
You can use animations to draw the user’s attention to an element and add a nice visual to reinforce the user’s action.
You can combine multiple animations to produce a finished visual effect for complex animations.
The SwiftUI animation system is robust and capable, but you can leverage other Apple frameworks when creating animations. SwiftUI lets you efficiently use them in your SwiftUI project.
SceneKit includes a particle system that works well to produce smoke, rain, confetti and fire.
Where to Go From Here?
Chapter 6: Introduction to Custom Animations and Chapter 7: Complex Custom Animations of this book go into more detail on using the AnimatableData and AnimatablePair protocols.
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.