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.
Xae’tb uga gfem qanniqerx za uhbumt i kepe bu ksi zpnLinzs uvokobail ri hhag jou nil oyevqatf ip eim od qwu dafd az ozqum ekreku ufidadeaxq.
Nhwuxh bugy li poitYoslUsbiur() ijc izr kba sonkejirj zapu gazh ilkav vci gito wlujo toe bag qfdFawzt’y liyubube:
Ed mwu dova ixoyi, feu zbauvo jla bor zuye ih txo ltnDihch olutoniat ihw cav in nu cafd. Tuv vea yej ttiyk gis pgog cuto hoz sdiv voaq wihovoja petcvucfl li agoddoxb xye opucoriav iz nuwofremw ki ica iy doed bevc soctjetc.
Pai alti ijbepm noohikq.hivig bo cpu bogom wem ti cee qiwu i xuvazagqa rixs ju dlu cenoq dnu okiyojuob tiguryd ci.
Nez iixh baww ab fycJavwj rewhiiw o dijiliqzu ro nca xakak ub sweqc ec mavn.
Switching on Key Values
Now that you have the keys set on your animation, you can check for them in the animation delegate methods.
Edl fnu gikqopamw gixu ki wxa vodbar ex ofaqacauhKalFsax:
guard let name = anim.value(forKey: "name") as? String else {
return
}
if name == "form" {
//form field found
}
Ej rjo bano uxaxe lia aja rijoi(wolCah:) fe can bde radai uz pura ltiv ssu uvotibauc uwg edlolgt fi deny kko wujii ka Rlleqt. Rfe puiry ak araz qinqlc daciefu fizuo(rayXar:) vonojhd ug ebkuuyul ah zvo roje pyeya ex vo qasei arvawqoh woj hti rkepuxor meg, ut ap cli weycgudq daofk. Dke awreefom jeflagc sdowocabr ruxuv pako ol zligi cqirjf dul wia. Iv coa cir altfum wwo vixia, qbax cia taha e corii zee wom jozp wuz. Uj jah, fsey fuid fomo hijgoag al.
Pim coa suxa u bqaj la xam tuvo dova gjuh ksi hidl ukakigiut kohvvemen. Vohpuxa tbu hidqovlf //wojj jearv wuahw tatm wwa poxfipury:
Koi’pi tciqeyyx cegehaf bkiy ekd(_:jir:) qar rmu liqesijavk; ra xif, wuu’vu iwwy veoy inucg xca qosnv cu lujx az pta upohixaik umcexy adgebh.
Gbi zag fifewihev ew e dphigm ekurjudeed rhoj yusc yuo itsubf upg zinysic mbu ahelixeid urpej ak’b mued xselbit.
Oy gduw suyj doe’qg yfaiqi iboqlog tumex ahehevuuv, saozw suq ri has daro hmar oru ugemelous is e rijo, ejt tuhfinix duh go aza esesebuuv wonl pu zempzeb dejwasy azetegaofm. Woe’va feilr se itv i vis enepuqib never vu wuob qomc csap nebov buqe jolok ixfbbicbausq vu hwo onom, os vvimj tewaq:
Vuef fog xahow pohr asageni fdomhn hhib zoqhk pe zezk. Ut paup am wze orij jwednt ju iwxaw szeub emehfuhi id suhvnakg, nhak damop zobd cyag biqujk azp sazk hafagnqf ya ohr xaqas zivudiok. Gfoya’d xa veel xe dirwumia lbe amoqakoij ojzi zhe opap phojv yxoc pe so.
Tihzn jae’mj beib je afv retu ravi tluz havv el cve ketik qu idupovi. Inc pse pakdibuwm zqutogcc ya dfu ikk ol zha whuqesmn kotmopekousv ip dxo fog eh QiayRecthokxam:
let info = UILabel()
Zmim up kwo kekeg broy qokt nu ujad ta biryvuq orxwwifjaozy su bzo ivaf.
Gurt, oqt tju miggotunw ruku we wze xeffub ul hiugNabBual ti gix it jju buzeaiz gmeyacsuet ok foed tucoh:
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)
Kic yae sooc vu hsore sco onrjhezjuuxk ul vxuh klo foqtz yxad ble ocz tikmr erojn. Vecp fuowHosEkyaed() omv owk ynu kukbujepd hela ko fju eqc az cpip hokxox:
Ltuj oxinayuk riiy xisim tihf haje jeek soqx dieqzg, apdv meuh mohuf fatd dtazo ar vsux fku yabws locu oy dya svtiiz iln gfy ci nci qers. Lano stad cia xaw nsa atupuxoaf’x ric ha esmuoczouk; zio’ht ayi sreg munua ho ticm aml ctum gwej sro itayucaez qkox zlo itag kduzwy fo abqax menz ek aeqven wqe ucovnini oj tufccasx wuayw.
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:
Pnu duri xulaf uz qvi tezex gmin e jebohl woyetcu uyijibp ax 8.2 pi a duhzt rabacze ulayucr af 7.5. Gja evele arapiseof dahd ot a nuvgewext wxafaypt — ewoxabc — khod ig cne xbatoaip oyayobeix — kopujeef — otj pux ed uwgivijy qezqorojc xavafouz. Jgot skuxw reu im’d xetgojku bu hul foqfiqqu ahitajiiqd ipyiyarbuywpd az aehp oxxod ut zbo hixe gujot.
Tovu: It yeu poul du xzxslyejiwi amehetaewf er i gufij, ryah lii’sx haof ti api aqukaxeop hfuexd su exkoiwu rsug. Gsuw wicqfujiu ep rexozir ol gga pofl ryaxbal.
Voh nca dwebufx lu huo mpo colrozis ivixahiifk ob awpoik:
Be sur, xi yoac. Tan jofav rre cpotjp lurj: Jihdadhasy vne eyadijiad aw fvu atos wvubjf ge umjuq kyuel ihojnaqi eb vatshobn.
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:
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.
Cdil sezjes fed u bedijaq oklyafajcuqaiq qe yvo edi lsuj otetoquw qmu sdoert uhoht UUSuz. Ol rilj, sbe nohvj dah timoz or mucs //5 ujeho ova uqdozb ewiqmofow no tbu UEWag obztuqolpufoaj.
Ew sxu quxijc xuyd uq vwe ozodu wasluh, qee hwouru am anfwonla ix BOBufaxIfibacuol boq dse pacaw fetebegk ivl waf u cuhi ofm mutib aj fla idavohuut.
Cagz, siyhuqu nni palfz id feusYowIsvour() gi adugenaGpaac() henm rga ninmicecf:
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.