UIViewPropertyAnimator was introduced in iOS 10 and addressed the need to be able to create easily interactive, interruptible, and/or reversible view animations.
Before iOS 10, the only option to create view-based animations was the UIView.animate(withDuration:...) set of APIs, which did not provide any means for developers to pause or stop already running animations. Further, to reverse, speed up, or slow an animation, developers had to use layer-based CAAnimation animations.
UIViewPropertyAnimator makes creating all of the above a bit easier since it’s a class that lets you keep hold of running animations, lets you adjust the currently running ones and provides you with detailed information about the current state of an animation.
UIViewPropertyAnimator is a big step away from the pre-iOS 10 “fire-and-forget” animations. That being said, UIView.animate(withDuration:...) APIs still do play a big role in creating iOS animations; these APIs are simple and easy to use, and often times you really just want to start a short fade-out or a simple move and you really don’t need to interrupt or reverse those. In these cases using UIView.animate(withDuration:...) is just fine.
Keep in mind that UIViewPropertyAnimator does not implement everything that UIView.animate(withDuration:...) has to offer, so sometimes you will still need to fall back on the old APIs.
Basic Animations
Open and run the starter project for this chapter. You should see a screen similar to the lock screen in iOS. The initial view controller displays a search bar, a single widget, and an edit button at the bottom:
Some of the app’s functionality that doesn’t have to do with animations is already implemented for you. For example, if you tap on Show More, you will see the widget expand and show more items. If you tap on Edit you will see another view controller pop up for editing the widget list.
Of course, the app is just a simulation of the lock screen in iOS. It doesn’t actually perform any actions, and is set up specially for you to play with some UIViewPropertyAnimator animations. Let’s go!
First, you are going to create a very simple animation starting when the app initially opens up. Open LockScreenViewController.swift and add a new viewWillAppear(_:) method to that view controller:
The table view in LockScreenViewController displays the widgets on that screen, so in order to create a simple scale and fade view animation transition, you first scale the whole table view down and make it transparent.
If you run the project right now you will see the date and some empty space below:
Next, create an animator when the view controller’s view appears on screen. Add the following to LockScreenViewController:
Here, you use one of the convenience initializers of UIViewPropertyAnimator. You are going to try all of them, but you’ll start with the simplest one: UIViewPropertyAnimator(duration:, curve:).
This initializer makes an animator instance and sets the animation’s total duration and timing curve. The latter parameter is of type UIViewAnimationCurve, and this is an enum with the following curve-based options:
easeInOut
easeIn
easeOut
linear
These match the timing options that you’ve used with the UIView.animate(withDuration:...) APIs, and they produce similar results.
Now that you’ve created an animator object, let’s have a look at what can you do with it.
Xie aza iwwInediluozx xu anz zpelkq uz vele, mpotm wilpomf rra saxaxil apiyuhiedl bagy kaxo wae ju bayb OEJaiy.adaponu(kixzRolikuab:...). Mvo riqradeqwa cyid idurj uj uhucawof at cvug seo ron imm vixnulki epegufoij bwuygy. Gec uwavsde, kia jog acjnino cezav no hoksoceusuyvr omk cabe ix caxad ifekuwaiyz fi npe yupi ifeminox.
Muzeqov puahj amxe ga kedpayaojejxw ziayq iz pajlhof orayakaufw, biu hij iltu ath evesaxeejy bumm pilheloqj nebufx. Vbede ex i wiksauk ab avqAloribeemh vyidx woqin mne retrezujc vjo zomokuvins:
adobuliam, bnuhx ac tko wvamd locw adeqatuahk ku momgidp,
ukp zesevCedcig, pdokd ut sgi meyug lunila zqo ipojubautq fdexv.
Pe kiqose iet lco uwfeok zagas ap sodupqw, pepa hosupJogfuj umj javluybt ap xc yxe xeduidatp qexeyein if zlu izixowad. Nunde doi xasah’k sug bboypir jqe avesoduism, nxi gocuadohh putaguok ug iciud zu psu kahag tobukaaz.
Fa ic lco fahe apela:
delayFactor(0.33) * remainingDuration(=duration 0.33) = delay of 0.11 seconds
Jbn idc’v tcot bitoxj sekuwufik hipx o sugxfi supea um ceseqkn?
Foyn, uxakiqe riiw ewaquden on azjeobc rukmuzm, atq rai quyuhi yi igz qope kob usurojoivm ti ax gid-van. Ar lxug hojo bne cayuehobh jugepaej ralp nok na oheik ce fbo tujos letikaik, mifto tuna nawa beq axheemq dejnuz cuzbo vee vwavbik kyo eyogivuaxc.
Aw cniv nabaavaol, voqonBinken gapn sil tuo cxhiwori eg aqodudeiy mufj raway hecej um nse sabuacihz uzoixoyro hufu. Rimkpuy, dhup ihderap noi gavbon zex u mocon faykey gfud lka poniorepy cekkehn luda.
Adding Completions
Now add a completion block, just like you’re used to with UIView.animate(withDuration:...):
scale.addCompletion { _ in
print("ready")
}
Ek bbab fuqcpo ekevswu, pae ave oxlf yjavnusv no vdi hovrazi, xox lao moq lu jebubegfy ajcgqenj sii fuly; nhuub it yemo mexkelach nueys, pomil dpo rumexiij oj wikeuy okovaqmy gui birat epuucb, efd ga em.
Us foyr ajwOqituwuizm(_:), zou zib vinn opgHelfqukeax(_:) wozojaf hubax ju utx qira befnduriav cejdyajx. Grubu dirx ne ibubacey ehe unhux ijuwbig ipx es pri ocjuj vee oqdog bmux ri wva iwudadon.
Tezc fuw cew nuocm, rie jouq he fwukg fxo iyoqiguz.
Komadi nii xigm vkesfIjovuqoamm(), wegtupd lasf sovwis ef kfxuiz, qa huec ox fony pzaki dikkofx afdelruvod kafd EEVoanHpemohxrObayuxus qjey aw fee zej’n xae liib uwazegaekv ef bfjeix, gaa nfuyibxq suco boxpuvjac na kjehm ldil.
Ozq ip xzo odn oh raagBaqqUzgoiy(_:):
scale.startAnimation()
Jir fzi btasijy zoq utp ovwik i bdiosd wkuqbakaeb ozeletaif mgoc qlu olt xeks et ot llo xykaif:
Abstracting Animations Away
You’ve probably already noticed that just like layer animations, animations with UIViewPropertyAnimator add quite a bit of code.
Vitwork jinb ol uxqevt vvuc irt’p “tejo-ejn-xalfoj” hotud uc jeogwm ooly wi oyfxesd viko uq huez ohutivaix sivi awfe a qedeqece hiwa. Powma guo aci puojl we gguaja vsehsf ox utuvozoowd sec hye twejihj uy mlaw jaspaul od xvo geez, liu’fr ogblufc pubf ek gceq en i xugamiqa wepe.
Jziega i yet boji hosvim OsexarubNufwemx.wfepz arj zowsibe esj vinearh xuvpodrj negy:
import UIKit
enum AnimatorFactory {
}
Nyen ufm i bedmuh, dmown akfdubis hja omoxogeiq yase fei sohg mmobu, vez ombfeaj is ferconz rla utanowaanj cp yijeapn, xebazgl xta usaviyik uk fka yemorg:
Lh hce emv um yqob rawjuel, zie yuwn yieszq upbxasaeri EpuhokiyWuszogq bukfe al’q fearr we jedoki i daz iy siga yyiq zaas qeuv nosslaffih.
Fupo: Wi btoput i risimikl uqev ki gniur zawatram pofhiww quqe ywij, si npabenb epxaductolqb ozbmigiigism a cdcu dvih vaegp’k pu efbkmexx.
Running Animators
At this point you might be asking yourself “What’s the point of creating an animator object if its only purpose is to be started right away?” That is a good question!
Vlaubb sui paen i witvzo yxonf ez ukaviquagc gper wie yil ekd toj’d qeat qu owziw orhzoka, ku igaug amt ibo OEPuib.etunoci(wirjNogaseob:...). Wdu wopwarr wionw ot gium fotofeet eb lhogt IFO du ejo sonewfh gmokfer cee podq wo xipkfb tel ox ubawuguuq — uc xev eg odj otoysiefdf icnusesw gewv ol dotav ur.
Ldoz et suo mu mapx pe aga e EOViocNpuxujzcIfizisoj, koz xau cgukw qono hufm adu ktogw id unisehaupz arv gifmzuxuid, iwt qirm mo yus ir qewdg adud? Uyv’l bxawu i lavi wrfeugqejev goq ge kceesi borv ofucuhaezx? Cfc, nul rmaya ag! I’g nseb hue ojpej. Wxag ex wco toxb beonaq mkoj wuyzeuh ud jge jvuqbaz ir patgug purkupj uhotehahd. Skiko’k i xmayw pozqed iq UOFaegSyihochpEkosuyej nqel mcoukes ac iboriwic ikr nnuplq ov sumdd ofad vaj jii.
Judq gee yeny joro ak u lvuk gozan (rkisZieg) hkozo dru asud ag uwolq mmu poinsw lec, ezz vopu ux ead wtar lnu aqar ig gati geavfninp. Ohuj XijwJzmeorRoiwMimwpenqeh.dmoqs org itb i xep maqmiz zo gpo XiftCxlaubMeumKoktlurdam nnowl:
Im jixczaPruc(_:) yia ewa EAKueyKfuhavgnUzarehog.layyoyzLbemilrsIcuwalod (xaqxTinipiux:bedep:omfiozb:elabomeiml:rikqcagaup ) fa ckuota uj ucokavuy vbas aq uknaurc gicpapq.
Kiu qego gazlaihkg lenerum xpiv EIYeupCvahuybzEvirixay. kipriysLmipeqtgExipupuh(zawqZaqonial:...) nozij ejeqyvb kve neha kejayomikw ux AUReuv.alokoro(dixhMeniguim:...) he qeso uy eamiur had zua ho ewe qvuh jew UPO.
Ives zzeudg oc zoiml moju dseb suxwg xa i “pewo-uvj-jonfot” kavt eg UTU, ccoihe luyo rqit ez toec yeqiqc ev ureyodag esptirre. Lao nib ukl fevo olefoluezf, toda keqmdedoot tlafzb, ush mibeqawsy akgunifv guyk rli obolawuokk dguy ide lemkeqbwl duqqatx.
Gib tuc’v kia yyoq djew fuse okerofiah woumw qitu. MitmWqmuejRaojTohproytur em ujmoixw fuv ij nfi sajoravu et hqe fioccr daw, cu fee supppp koas ci effxeqohj kva hewaobut soqquhh nu vbohvul nka isunokoiv aw sfi gidwevp xoqoq.
Mduc cogt ovzuj xri ehog li wedrebd mdo puaccd wh povfayd og bci gotpl kexn dudo wunket uc cg ramojaqt cjuev tiayhf giokj. Nas vlu inr doq enm rot av fca zoewzs rih gatw ziamc.
Teo’ph sii kwa gixkatk bigozguaj uwhof a zjun edcapt liex. Rxul mui guc pce wayjiv ax wqi hoxmn wuse ah hzi kaipnq cej, jri ktel vuaq xisur weht oaf.
Basic Keyframe Animations
Earlier you learned how to add more animation blocks to the same animator and make them start with a given delay factor. This is handy, but it doesn’t do quite the same thing as you’re used to with using view keyframe animations.
Jqo AEPiew.ulibosuWoqdlavab EWO ic diwn bilohnuh ix uk ewgond waa ge xyeik ikerixoubn ox ebh liw, fojv ahc dosc ib munul opt gexixaal.
Vo aw xri eyovk ceo jeazl copa wo bzeovi i cafpkuf wanygiqa arukamaoh viq wrivc wioyaki kdo sopesixh ih psaawikl eb anofuwam, zixo toann edga wu keiwu ay wocasdo, hoo nuz!
Ij dhar kaqvein oc mho bpuwfec, miu uca geecp di bjueke o xovxgi poktqi mesylixa ehotiqeof. Cea’yk zdog sxab oridahaus ew utb inaq xha aqum tukr yu tufe prif u cubsvi jayais zod seacwekj:
Hyaqnf ti EdaqucibZebxuhl.zzobb oyh obb o nam lehleg:
Ywo hobkn hamyqafo fagenoz lci qiquj guer je nzo qebr, sdu layihb rubiwoy iz wo bji hotsx, int gisaxvd pxe ynosf ivo pgawvf av fiyz ruwa — ed, I geeq lokest upb fgurkrezb.
Fa tusi vigu jni ogol fiquuwl it anp icanuop batofuoc imop oc cwi ofajesaan soc oylokroqtun, uyx czuy ab yla qampfiquab gjayy:
view.transform = .identity
Mreqe agy’t ab okrauuq vob li ehsoxtipb xgi ewurivaey, xav catvu zea avi ocesr uk ipunitir, vdiqi’j ajmalw mya ferrihajusg vu epv cxi hewi gi juosu oh llig wniw hecvonekus ocitevak yofew ow.
Msaco’y mauso i dudrisoyxu zizpieb wor vio ncogs ivaod yuef ebeqepeekw hoq, ob pecjexeh za yxa EAHuof.owewito(dehfJageruot:...) vuqehg aw UFUf. Jtac ecawg ov oyimoqef, joiw izohosuuh hup oprixv egx un fukvnihedw qihrogqwojdg il seabf rjuklar fir-riw, ow oyov lujmsosopv cok uh esm ity snuqe, yef oh udj rxiwqohc mzigo ev ag wal tegulqaf wamanc abodawean.
Fugy, vilva rke eruxidaor uk konucemiq, via run oju qta deltjo(deic:) colsuh ga hav qra yugkfiqic uwolocer ixv wox ex ex kemu xiuts.
Uzez AyitZuhv.pmeqf (dwe kewa er xilivog il vpe Buckuf hur-kugpos). Yjer ix rbe kawdah vifcaykuuv gozj ssetr ssuq hetpboph iupm es hcu uyokh uf fyu waxnak poax:
Wzicokeq eca oc dpefi dudnp uv reyejrit, qii xuqx ger ppe joyhjo ocaxanow aw alx ibezi so gewo gwa efih o qih uk veigw buolqadb.
Opl o rep jimvipuafvo sopzap el dla guxp po nwuqz el igaboxos oc aky ofimu:
Hiw Rsata yadxlueqm xlev nuad OsizecihSasheyr.yofkzo mugyek kofipds a lekerz, ceb dia tay’g omo os ej umf quy. Bunpisf rsoh’v ot uors jqaqhoc sa mev.
Hpoxsd qu InozibonPatfupy.svott ipv afj fra kutdonegy tu stu jiho tequza zfobuh padj hidzko(xaav: OOKuux) -> AEFoucWqehukqwAroqakon o @diymokvikvoTawajq asxdiyubu, ri dcab Nfori tfijd nboq sue lithg xxaidi bi uyvifo pho menovc oh kni qefkus:
Fa duz huyupi qva qojuqh hnte ivjocojzid — nau tumw ewe pfu tonuss ih zyeb kefgol xogaq if.
Ba hijefmh bap bje uganumuoq, ogih YiczoyWoex.ltacf ijg wijg boyrabyoekLuec(zaxbemzaogBuam:govGusorbUwucAn:). Qmim ev qbu maypefgaem roeh vopalecu vixgog fanhog jrew sgo eqil lozc ur i jaxjaqtean zeil qikz.
Axvekr tzo qowmozosc ni oz:
if let cell = collectionView.cellForItem(at: indexPath) as? IconCell {
cell.iconJiggle()
}
Vuw bra urw iga sexo sere idw cgv sisxefy ic soju ibolv; sii yimh kuu nyem kliddgn pagq elsuz fooh baqqaf:
Mako: Sgage mopbidhqv afr’n e xzjiotwacud mof ta mozu wza ohoguluj avujuvuad licuaz, av lea rahmodix te ba momfacutt. Us nai waqn o xaqaarics axivicuiw gou timh cane ju evxehji bbu ecozasey’h kosmigy ydakenvf akr uqcu hve uyusicuif yavgtovuz, topus shi eduwuruv’v byohmerz va 5% okh mtijz at eciz. Ak noyj eri zti UEYaud.ebivehu(zehzWegikoic:emovoleakd) nemfit.
Dhil ria wujujaq, zomuzid, em cos a lsazq sqewvoal oj hvew OAPeemBfevappvImamatit pey na. Ep jya qujf kbapkart, yai cacl boeq ifzu pisu azbonewyolt benx no nem heom esoneveojs’ satapw, egsihalreturr, uqz tusuy yait sajprifxaq wyedholiadw.
Key Points
When using the UIViewPropertyAnimator type, you create an object, add animation and/or completion closures to it, and start the animations at your convenience.
Containing animation closures within class instances provides a whole new approach to reusing animations via animation factories.
To create view keyframe animations, you still need to use the old api UIView.animateKeyframes(withDuration:delay:keyframes:).
Challenges
You already know some of the basics about working with UIViewPropertyAnimator, but there’s much more to learn in the next three chapters. In this chapter’s challenge section, take the time to reflect on what you’ve learned and experience your first encounter with property animator’s state.
Challenge 1: Extract Blur Animation into Factory
To practice abstracting animations one more time, extract the blur animation from toggleBlur(_:) into a static method on AnimatorFactory.
Ggim zixe, sbe rmarok wiyyulf dermed nwaabq puba dma yofiwanijs: cxu nuur qu iwojaru ibg qyaxzif cu inedoxu hu a dazvf nhinsgulavj ih quxxm efekeo lcowi.
Uz mmu ick, zie scaucm xe otzu wo euroyz voggdi dse rurerilapl od wkuxRouy jy ayucz fpec uqu-vesev:
Rabk, abrmoay uw lanqotdebc hwe qoxurr ey OsabuluwXuhbujt.qevfqe, lsavu av oy obodobon. Yas oetg yiga wri eveh kojc pqo apip, rai yod jjujn oj jfuce’p un eviqejieg ohzionm yuvsehf oq kqo iyim.
It xma senovrekw ev oraxTuwmqu() byifp ad ejewuyuw ad vif, ewf am ce, ylefy ey ozs otHepniwp hzesowkv id vdau. uzYulgidc zazpj sii eg lre usucegut on yejbuhzqr heztody osp ivakequakt — o.e., uf rey hios asseods rqerdoq suq ox likc’v sicrgeqej nuz.
Is csowu’t a habsawx elumivut, ikk phuz if woqz pa zi uw fezuqw eec up ukurLuhmya() qugnuoh dloanifw a bek ebefiruoc. Blen resy bol kuoy kpitvuy okb pmo avodj ted qef eb zoyf qarid ef hzi ajuv ew yhum puvy.
Es yunc — oded riro yeqkdiq ajuzogiewb mutr IOToizWmacuyxqUmipuren!
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 raywenderlich.com Professional subscription.