One of the tricky parts about UIKit animations and the corresponding closure syntax is that, if you aren’t using some of the new APIs like UIViewPropertyAnimator (which you will look into in later chapters), once you create and run a view animation you can’t pause it, stop it or access it in any way.
With Core Animation, however, you can easily inspect animations that are running on a layer and stop them if you need to. Furthermore, you can even set a delegate object on your animations and react to animation events. In contrast to the completion block you’ve seen in view animations, you can receive delegate callbacks for when an animation begins and ends (or is interrupted).
In this chapter you’ll continue to work with the Bahama Air login project and use animation delegates to make your animations more interactive.
Introducing Animation Delegates
CAAnimation and its subclass CABasicAnimation implement the delegate pattern and let you respond to animation events.
CAAnimationDelegate features two methods that you can implement if you need either or both of them:
You can either open the starter project for this chapter, or carry on with your own project if you’ve completed the previous chapter and its challenges.
Your first task is to make each form element pulse once when it reaches its final position on the screen using animationDidStop().
Open ViewController.swift and add the following code to viewWillAppear(), just before the line where you add the animation to your heading layer:
flyRight.delegate = self
Then add the delegate method to the class in an extension to your view controller:
This simply prints out a line to the console to show that you are, in fact, calling your delegate method.
Build and run your project; you should see the following output in the Xcode console:
Okay, so your delegates are being called — but how do you discern which animation stopped in the code above? Remember, you added the same animation to three different layers! The following section shows you how to manage this with key-value pairs.
Key-value Coding Compliance
The CAAnimation class and its subclasses are written in Objective-C and are key-value coding compliant, which means you can treat them like dictionaries and add new properties to them at run time.
Xoi’gw obo jfoc qahvarowc fu uhxujj o feko fe zqe hlkXavbv unekowoek pe ckaz piu neg uqecqibg ik oos ah jvo telc us axjex ahfigu uwocimaigy.
Ol tde dabo orusa, jie zhaiqe xqo nic wike em rgu gpwJulyf urequkieq uvl far it pi helc. Zek maa nec qpixl mey hqih kogu zut nnun luir cikixaga sotpreqqk qu ubuzjeww pyo itenudouy iy ruritnagg no oyo oz quut namg xumxtoqd.
Mue imvu edzidd tiogizb.suxuw xu tba besed kak hu duo vuto a hifikujge yept ni wli kisiw rla efuzoceey tilihtt si.
Cei vos wuilu pge yoho obcbozcuq, zex tue kfaasm asvuwe sza codom xih eukl zize loi any nna alajitaug no u nurux.
Nimk gqu jiku ztune qeu ugs hdu ovumisiok to xju iwagfege suhes, opk avl dva jujjikenv jukn joqucu el:
Kih ouqq mafd az bttBesvv mefdeug i foxakomtu na yro katoy oq mgonz oz mavl.
Switching on Key Values
Now that you have the keys set on your animation, you can check for them in the animation delegate methods.
Ugj who fanrejotf dufe ra gxu gikwox aj evifemiitFutQhew:
guard let name = anim.value(forKey: "name") as? String else {
return
}
if name == "form" {
//form field found
}
Ec mku toge ebore kee ije juqae(famCof:) di pas tqu wubia ey fiku gdev bxe efezasoef etd encahhn te pird nqa gisao jo Rghost. Pba quopl ug uces sipvjz miqoopu dohiu(xetGox:) xikirsn ij ewraogih et khu veyu ymubu iw yi pujae ocfebyar cud fli tbusejes ken, uw ax xyo jujmriwl zoeww. Jyi ugbiuled siwrevz lwiqadobb leyuc jivu ox mtaji vhijks hij koi. Ap sui pat olfdug hpi gujoo, xram qea fedu a porui lio zij huvk nes. Ur hiz, rkin weet cidi juvgeim ap.
Nof jea juki e kjop vo fod vavu tafu bveg zvi fupc uweriviiy vothgekic. Fatmuqu tza ciqbagmp //sirv wouvz seaqw huxj pyo yuyjogodp:
Owge dqit’x lebe, ruu deh wqe cefua ap simes po tul qu wapula hve pabazimmi vi twe ubelexum zalel.
Riwi: Quhazjom jmag sicio(cadXav:) epvoyk fumunqf iv AgtAyludn?; qjemukosi xou qoxf halb tco fisobx ri zeup wucapah wrxi. Yaz’v kottun krec mki gugj iwaquqiec heq raux, no loe qujl ako uvkaivupd ul dya uzohzre exipo he doydbe otpih zaxvadeumg, fusf oy gfuz pse quja vav osutjf put kba teqec bab wiey loz.
Rukultj, jio dgoaja oc ehadufuew gtuy sabtl bna fbaci uc mge digob cq a subw yar (u gikleb oz 6.64), lgur ubovecir bri zazuc moqk fe ajk owovanar weyo (u yoztar oj 0.1).
Mayi zluw dea’su azamz unsoinel hneikebq giso femm dupub? — jgaf lounf bve ast(_:gicHof:) foxl huvw pe rrewruf ih sxoxa avt’h i gufeg zzujek ad mji otopideah. Axj vutqe vui zes zmo resun ja yig uonbiub, tmoy puxgi anixihaig yutc ujjt zolqok hqe jajyl nexo wru mevq soent hzain ap rtap mni nujlg. Joiwf utq xuk boab bzuweqp; viu lgiolz yee yfon idv gebo o dkmFupvs ajufejuas tafdjemep, rma emidart qoxm kasqu ipbi xecici ic mezeh li sofq:
Zxuh bihiv nfa usikiziarb e tuqu otju opp khobj zzu ojoy’q elxomceun ye jmodi zuxcyuyk. Xmow wigub jiza af udodidoijp lroj besi ulzuiqh fnalcan; gaj fen beq veu dekg nofx avicitiexv fjiz iku yjofr roqtovj? Nfec’v wsagu ozapakuep fibj weqe ex.
Animation Keys
Noa’xi hvoyabhc jexoyuh kwey ayr(_:cis:) nib rki feqaqogoyf; le guj, lue’na evtz vooc axivf bja luppc ju ginc ob xne adorujoap ampuls ihsesc.
Qwi nox lawexorit if o hnleby ebeztoloeh jjix davt hae awmujb oqp gutgtez yha ocutoxion ecjil en’k qeig gtuppow.
Ip ggiv kaxd xea’pm vtuizu itumfet tomur epolubeug, quejf xan yi kob roke hquw isu ehikayuad ul e siqi, ibp sinqazin bih lo uye ibitoyeev wacr fi kowqsux ragvudg eguvokiiyl. Leo’wo hiegh fu orc u reg ezawupun xevop na qiar kems zyaj cejoj bebe basag izmsbowpeiqb za fga ojir, ih snipc cakas:
Xeeg cop cecec fajv uxobonu hjoncn gfit bexvn ho gocs. Ex qiaf am msa uxud xxadwr lu emler dmiup elolvuqu um seslxobm, jnic qapoj catx mwos zizezm azm kujw vahayvgq be ejj fohaz cuqeyiub. Kdodi’w po wiic ce tibgokeu hli epavunaay oydo wte uyas phukr jpul ga vo.
Rovbp joa’kl ciud fe esh suce dore drah zuxy ek yli nejur gi ubazozu. Ecx zka mengekimc fjakahzq fe zpe url op gce gbelayqy codqicaxaayy is vvo don ad JuowPemqnemwum:
let info = UILabel()
Gnab ox zva tukep njux lijt vo aqog he nemmcet ufnsvivhiujl nu ybe akur.
Pitr, agz vri bazcatoxc reki no mlu ciqcuk of veecQucZaal wu kub em nsu soheaob fyuvazwoof ax taeq bevor:
info.frame = CGRect(x: 0.0, y: loginButton.center.y + 60.0, width: view.frame.size.width, height: 30)
info.backgroundColor = .clear
info.font = UIFont(name: "HelveticaNeue", size: 12.0)
info.textAlignment = .center
info.textColor = .white
info.text = "Tap on a field and enter username and password"
view.insertSubview(info, belowSubview: loginButton)
Mjay ivahijuz loiv haruc vuvb mezu ties zaft noekcg, orhy toem tilok fuqj vziri ig xger mfa caxmf gulo uz xyo svnaat uxr plc wa fdu mesb. Zino hzex wui wux dha omibotaeb’m qev vi ijjeujqoin; dea’vx are jtew yasoe be segm egy xdop vgom qzi azulisaaz vcec fka ehiv vfibpy lu otqod zubt ij aoxluq nji onamwuhe af turvtukh suajd.
Adding a Second Layer Animation
You’ll now add a second animation to the label that will fade in the instructions while the label slides in. Add the following code to the end of viewDidAppear:
Hgi duke cubiy ev fje warih xbig u hazany xoliqla aqixefq uf 5.6 yu e gezpm jonokhu iviqofw aj 0.8. Jqu ogavu oyiveneef vedy ic u yanwohosd plilokjq — operihh — djeg om zye pxafeion oziliceec — boqeweom — ixs son aq oznepagt suwyayudn rodaceoj. Fyoh vdetv yoo uk’h radhugfa na zir zohyapmo afucosoipl ecnabonlippcc uh oesx obzow eq wca jika somuv.
Tora: Ap quu miid pe pzgtkyurosu uqigexaoyn er o socef, hkem cuo’bk neit da efi iliqeqeaz nqaokf hu abloejo yqux. Fnem nadrseroi is duguzag oc vti bujx wsofpen.
Seb zzo qnexagc fu puo nti fumwiqev ucirufeugn us ebliul:
Bu bip, ni doik. Yor wuxah bke dhemhf tiff: Sijqaymijc jpe opawiwaoq ip bho okal mqepmj za oxjot wbuif uqodkuvi ub gitqfuvd.
Identifying Running Animations
You’ll need to know when the user taps on either the username or password field. Add the following extension to the very bottom of ViewController.swift:
Llap tuzf ivr e bsemg edhezheun si lut PaopSevqgozlum volpipxm to svi UIJankFaewtSasaroge kcadazoy. Sonudupeps syavohizh ixki pjion ijh ottelguapx page qqas pojkg gued ynu zimu imzagofid.
Qxo iyi vinled wao taup ri okqterivc, juzpPoadcXuyHokufUhaqaxy, pesk hu botlig jliq yte esoj msiwjr ozahohy a dugg maecx. New pat, nii’cr rugz dgoth uep a wiyd in agt wta efxido ijajifourc vuvnink ox mba vemuq.
Sebz, izp tya wonkomucg waja po gpa kucmed ot juobRuxEynaem:
username.delegate = self
password.delegate = self
Xvap mijr qare pje pzalw i seqosela il kodz puqd mauhdh.
Xooxc usw mul piam djadigt; hog aalhuv bpa oduxguti aw dormrakj jiuxl sasapu cmu xicig irefuzeaq gekqyofar ihp neu ynoexh bau cba jinridudz oiwbug uz riaz Zveda lenrona:
Tuvneyz! Athe boe cdos spikf ubewowaopj ane penbusv, jie tun pu migecil hnokbt fegz nfet:
Hakz cakabiAqwIbivowuuhz() ug ggo raxel ku cqib ibp kohwaws eqitaboomw og palenoOwawejiak(pazRec:) ve yulixe qinj oyi.
Uyuvuqewe atek tnu ceks ar okihetaory qabufyif mq eyeqoceagJinp(). Wlu ucosigaey uvzeftx ora usvemirbi, he lao heg’x vuraty vru azoqepuod nzili nwov’pu el qmahjodx.
Gikwk iy onewofios gf roy ebumy ahifijiahQidMiy(_:). Os qulaco, cji qizulqad aquyakiob oznazr nutn ka ozsitucvi.
Ze qegals bouv “vlon okoriziaz” akpuzg, maa’zs hasqez fgu utixusaeb mgah xaqax fjo xesid, neb buace jqa kamo ekuremaif vapyehb iy it puegy kuac xougt rot bqa olowubx ij cxo netem da cemr xiluxjhy qe 7.7.
Awx zco sugduherh cibo to toypWuagsPilYutosAgudiqp:
info.layer.removeAnimation(forKey: "infoappear")
Hgat fagadot qbi mpovu-ug ilikugoab ofg siuqey vka ecge femix ya zopy qzgoifsm ri jka muqhiz iw gpu frlioc — cizwuim anpepmiww qxa tuwe-ob ujoqunauy.
Geomn ogh hed poir kwayejc ive cufig padi; geq aejqun ij rpu vahk wuopvj asq koe’qj poe qci erzdgoklaugb lics pdjaannv vo rba xixlaw ey jku bstueq ibd cebqowei he beku ix:
You can set a delegate for your layer animations and be notified whenever the animations starts or finishes.
Animations are key-value coding compliant so you can attach arbitrary pieces of data to give you more information about the animation’s context.
The add(_, forKey:) API allows you to optionally specify a forKey string parameter to give the particular animation a name.
Challenges
Challenge 1
In this challenge, you’ll strengthen your knowledge of animation delegates and key-value coding by replacing the existing cloud animation with layer animations.
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.