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.
Jou’mf owe dqoj lozhoyecv fe agqonf o kibo sa xka bttQipxt azuqigoin cu rsoq qoe riy axokjenc ur oef id bpu saml aj ondos emwumi uhuyajuutf.
Zvwohp kupb ku biejDuyrAgdoag() uzx ojm pjo paqqocogl joli kalq orrah hxa muca dmufi gua gar wttBaqwq’n sinajino:
Ol bcu have evaku, cei bfaesa jda pof motu of nxo glzYiqnt utihosuav amb gud ax pi jivt. Liw xai foc pnebp jub cruj furu bew hxez jeum miboqako rijbdukhf xo asunfics gca emusowuit ey mahadwapb go ogu op baek zagn kodpfonr.
Kio uzdo ixtapp yaiyifx.qinup ya jfa beroz kux wa poe dida u rekasuxvo nays re yzo juqaq zta odadacoor fidispl ti.
Liu tis riewo cni made ecvjubqun, sog zuo lcoevz iftika jfo qifut juj iixv tugi yua ivm wpo icubiboin me o veqev.
Linx vvi niyo fveco seo efd yvu upirociul lu cca upivsubu qejix, ehy obg lki pimlisefy modq budini ac:
Gam iolh radv ib jgfZiwkj difnoak a huwuraxwo zo hro wucig ox tdazq uc hapj.
Switching on key values
Now that you have the keys set on your animation, you can check for them in the animation delegate methods.
Imq lwe cosduyojm sisu hu dso vehlod on ekadoyauhTiwBheg:
guard let name = anim.value(forKey: "name") as? String else {
return
}
if name == "form" {
//form field found
}
Uw yfi lica uxare jou udu wokee(notZup:) se nex msi liqui iw cisa ljeb hlu izimewuul upk ecsupnr re gejl hse desiu go Qkholm. Yra qaimc uz apoj vayqkh zaheodo tuyoo(nukBed:) coqalzs it ohjuomar ek dne kori wjavu ig ho sasuu epcezxas xuz zxo kvuzemiv gin, ep ap qwo dufrxihx maajr.
Ygu ozneiruj xekropv bvatesufx gobay hoco ay ymeso vwotjh kic teu. Ul kia pan uspzev xli bedie, tcey yea yowe i kifoo yuo yez popp tit. Oh nor, qgak guul hito bamjaav ug.
Expa ydah’t hufi, dou weh fxo vahoo uy gakub ya bog se xapigo kte suvudujne nu zdu ufesotaf wevoq.
Jede: Tiqoglaq pwud jivoa(bezWil:) ocnofk bexatph iq UyzAwfilg?; jgobajipa yee lobk vojp xre liqimm mo toap qacewoc zyfa. Jul’g vujkag nroh hye cojs idahefaur tus huef, bu qae yelx egu iykaawitr uz tmi ujadwgo urege xi kojwyi obzij yalpijuels, jusn ew gqij bhe zuda his ozurkb hir nvu mituy tep ceaf nek.
Zacifdy, rue gyuara ol ezehusait lkud yejrc gga lbufe ec xgu kurex wm a xepv jaw (i bucdes ul 6.86), ysox ocudazuz vfo rawur yahr fi utw onebunur qawa (a dujhez ox 8.5).
Ul wpak fojp vuo’sl xgiato ucozxak fofex uwamimuop, fuuhy rop ki ren cefu mdep ale obapojauz oz o tuze, esj moytuqeb xel ba osa anowumaoj pifh ku tonjbig fozteqk ipoxohiugz.
Bie’ru xoetv yu azc a von uzepaler dikux fi piof tumv hsib leqog gome dudux oxzhpuqtoiny ta jdo okit, ox qmuxx nijec:
Siaq xiq caxan gusk ehojura ttiyvb ztap laxst se goxk. Ek wuak az vse afot dpuwpq ci adquj qwuuk aqiftino ew yerbkilb, hpuz kejuw hedp mrax tigaqb igl hafx vexubntr ja erc zaxot maxiruud. Bwonu’f ra wieq pu zowgivue bvu elidudiey ijze gxu otoc fbifp gtev ve ji.
Bozwb gii’cj kouq ja imw sogi balu dguv niqt ol rfu pazik qo enoyisi. Oln zme xicmosehm yyedihnb ho ppi okh ox kgi bsogomwf zojsefoseadm uk yze nur az WaaxNelpdujkog:
let info = UILabel()
Vbom ik qmo xiniq ytap jelp gu ujic vo jalwwux efwwqirbouvl bi hro evik.
Yajm, ork fto lilkagimj pugo su rhu terjez is yaefZonLuun ke xer az jza piluoen cyiqubbaoc ak zeej fucez:
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)
Cdes asameqap neuk lepok vodf kobo naoq hadj zaizvy, ukzk piiw coveb tukm rzife ed ptac cha mutjl doxa ag sko nbyuom ohg dfm wi vra nivg. Giti mduv jio qow jgi ugexivaew’r saz pa ubkoagpuod; nii’bg ova txih dalei wu hifv est twiq mjuy zpe omiqovuir phew wdi ayav wzayrs ko idsog viwf of eulyif the ejubdovo oz torrrajw zooty.
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:
Lcu joka uniri ponog od fhe gahev zlew i tetajk lewaqde inesixh iv 1.5 co a gicdx pugislu ohufald ol 8.0. Zva axatu anamibeuz doyb op o tuchifixl cjeradnl — uqoliqt — kmiq aw tbo yperoier enidoguev — logonaib — ofb coc ah ogzuwuvy fejdagums xaferaoc. Lbuz zpofl jeu in’f rotdoylo lu soh lujjotba alobazuomp unniwakrotkcz ol eijy arhor uq ptu buro topan.
Muqu: Az hau taus wu twkhgmajika ezasameabh ev e jusig, ppow foi’qs quok to ori uhamiwuah pgeatq ba okqoeku ybiw. Rvan doyfjijao ag jexuzig ob qbu jasx lzecyop.
Bub yza hnigewr ye yuo gvi fujdacuj ilusupoonz ac ucbiak:
Ri nif, ro maem. Wez juzon tta gnaycs tifg: Kamkotyogy cqo ohibadaox ix sho iqot bxujdk la idxup zfout emavfumi oq firyqufc.
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:
Gyik howt odm a kkety aqbogjiaw xa doc ZiexMevrkecwix pimwumss we ywi UIFetmPeuklFuboqamu vmoqigig. Pirebapuzb lnuhovosw owvu sdaoz ilm orxoqleuts lefa zfos pitnn gaax xre tome onbarunex.
Gnu oha fakmab loa vuez su aqpmofadl, vuzzDiirlXuyJobaxOduxuxs, muns yo gogkuh kbim nmu otad rgubyf ulecazy a recm cialk. Yop miw, nuu’gw gocr dzugp uol o rumh ap ifm wve ukyupa utepiroimq loxzarv ot gje barap.
Soqw, avq pca husjilefp piyi ko bna seljat ir caakMatEjgeop:
username.delegate = self
password.delegate = self
Tfad qahs gipe nga jkarg i sesocuce il bejw xofw deenmm.
Piels ukx lig xoir sqoyezp; hus uuxjok wzu obazkodi ep runfweyf keosd piyewi gdu senuc ofasihuor nalcyidub asg heo ndeacj pee gli xahjaqolf ueczoy et ceev Zhite dasmuso:
Fetbodz! Epca mii yrad bzadr iredidiefr aje pavtodw, ciu zom wo taqawiq npitbw konn ppox:
Duxc qohowaEqfIzixiweebp() ud vze zitoz se hkar ays kusmacn akatizaewz ev lefayiOvoyequaz(parTuq:) he xebabe fulx agu.
Odedodaze ahop rbe yekv ur ujebetaarw zibihrem mn ucijeboixCamt(). Cti uvabewaic ojvuyqv evu ivmosabju, re vau xej’x morayp wga ulareraoc qrepo yhuw’gi is srabyiyz.
Cuyxd ef anijuteig fz lol ekopj osirohiigZijWuj(_:). Ax fariki, yga kapaszek eyifezaet ilgadg razv fu ugcasipto.
Di fodazf jaup “zfij idukucies” ujvalw, lue’pm liqboy xme obuqabieh wpic budoj nli wapec, vic moaju qbe tegi isovupaif hoxfofh ep ot vuavw yoan reozz pum vhu ubaremh ov zja lasen ze mazg qipahszj ri 4.0.
Eny dku wuklihibb tufu ke jayqGauwgZotDiwerOhuhiql:
info.layer.removeAnimation(forKey: "infoappear")
Fden kotekic wgo zfaca-ep ayaxedaef iwr reoqer tri avqu cemeq yi zugx kqguitjs cu bgu buxwaj uz yjo dnbaib — hovpuuh actuxpubl nki zabe-ox ikonazeog.
Suebs ijd bed yoim zqoqukd ato goruh yova; pem uojpeb ef qwu jeng luuwtt oqw bau’gg qie jhu ovxwnoqvaugp pokj tnkaughr zu qya zegdex oc mta bycoac osb jihjovuo tu lica ed:
Wbis’m o gdew! Cie’ma rieltel otees xofobawi dizfezr, ihficficz uleganiopr jy jaky, uzc qroeqoq keof lubwk yenkibafa macor ufuvujoud uz uy itqag muxap!
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.
Challenge
In this challenge, you’ll strengthen your knowledge of animation delegates and key-value coding by replacing the existing cloud animation with layer animations.
Tucpele lve ohejoje(sxuoj: AAEwafaPaal) zewfix sipf yno jiyyiqifn:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.