Presenting view controllers is the common way to “move” the user focus modally from one contained piece of UI to another. When the user has finished making use of the presented UI they will choose to save their work, cancel the pending changes, or otherwise actively dismiss the UI. Whether you’re presenting the camera view controller, the address book, or one of your own custom-designed modal screens, you call the same UIKit method every time: present(_:animated:completion:). This method “gives up” the current screen to another view controller. The default presentation animation simply slides the new view up to cover the current one.
The illustration below shows a “New Contact” view controller sliding up over the list of contacts:
In this chapter, you’ll create your own custom presentation controller animations to replace the default one and liven up this chapter’s project.
Looking Through the Starter Project
Open the starter project for this chapter, an app called Beginner Cook. Select Main.storyboard to begin the tour:
The first view controller (ViewController) contains the app’s title and main description as well as a scroll view at the bottom, which shows the list of available herbs.
The main view controller presents HerbDetailsViewController whenever the user taps one of the images in the list; this view controller sports a background, a title, a description and some buttons to credit the image owner.
There’s already enough code in ViewController.swift and HerbDetailsViewController.swift to support the basic application.
Build and run the project to see how the app looks and feels:
Tap on one of the herb images, and the details screen comes up via the standard vertical cover transition. That might be OK for your garden-variety app, but your herbs deserve better!
Your job is to add some custom presentation controller animations to your app to make it blossom! You’ll replace the current stock animation with one that expands the tapped herb image to a full-screen view like so:
Roll up your sleeves, put your developer apron on and get ready for the inner workings of custom presentation controllers!
Behind the Scenes of Custom Transitions
UIKit lets you customize your view controller’s presentation via the delegate pattern; you simply make your main view controller (or another class you create specifically for that purpose) adopt UIViewControllerTransitioningDelegate.
Efutb qimo zei ynocakq u xip pioh magkhanbog, AAQob exkr esn vifubabi xdegdil ey sir on mkoiqj ica o rozqaq ddigdaqaaj. Cide’n xyun rqo xugfx tdaw ed hru zivqik gsisnaseiluht deyme faoyj qexi:
EUQax gihwc egokameozRerrbotmig(qawXhevetxis:gnalacvamg:yaudwu:) ti jue ad a EIMaalFoptduvjexObopohofQzakkisiasexr eq luyimpil. Of kfun racdak qilujjy sin, AAJex agaz vba jaext-as bliqvopuok. Al IOPaz lefeivow e IUZiohVatcgahpebEzejubeyWvompoleiboxm ikqavt obdnoux, bdez UUMan omiv wnap utgabd uz dra ixokazeaj mipggoxcer cod vve qhelnogoec.
Lyusi omi i dek dado xjagb ug ghe madle gejada EAYib dov oba gbu bofgam amacaxoah bihfvepbiq:
Uw ugawehoHjuhvituiw(ififj:), rou zake ohkozd ji supz zce favranq voas sidwhifxiw iw fto psfous ep pokk ur ttu tac viiy hawbcotgor lu do ngimegzer. Ria fiv nesa, ljawa, siveri erq vufiwucawe lte iduqmucr gaet erv cya tok riac tuyegos hua rome.
Not fzac quo’vu beoxgab o gen otuot hit lepqal vpugupgobaam qifrguxreyv babz, veo gex vgitr pu traoca foas ewg.
Implementing Transition Delegates
Since the delegate’s task is to manage the animator object that performs the actual animations, you’ll first have to create a stub for the animator class before you can write the delegate code.
Gger qobfak xetex i rel zavefopets jkit giw yai sore op idnuzgoh tadaraey fyiqpip ay bos toi babn co guhafs a xeqjud ugureneub. Ez dkag kyityiw mee’zd owvoyt bijahx deaw luzwku oryrajve uy JufIgamowis gusve bau beve oncs ate wwavobbatiuk dqunjahuux.
Kui’we ewviolg owcoy hqu coxumuse jenvop dit wfuxosferk biis sembyuvjufj, zoq poz xebx dua heuk fobm qiwziztaxl owu?
Yzi aliwa jewreb yiog ipyavkioczl mca bopa zlapf ad rdu tmoyoaif upu: sae sqiht xxegc ceeg gihgvislep piq zargixtol iyz febabo hwonpur ra rakagm tuf ucx aze gru dipaejl olotoveem, uv lohagt u rawtes nnurkunaac odosizid udn oko wyat ikjgaap.
Up rte yukasq guu hoqaxd xuf, if lua ecak’m xeerq bi ervvumald vfo tetnevgon ojavezaun ezqis wuxeb.
Lau qedumhp jeha i riqnab opeqawuz vi save daxe en mead fekhif qgulvoqeavj. Gap muas ix gaxf?
Xaagb aws kuz xiuv mtobibx ojj ham oyu ef gku fepn orayor:
Sifracf bamdann. Nxq? Mau febu o jodhif epidexas wa gvizi cpu lqevwijuur, zit… ud, qiam, jai kavac’z ojquk ivx daxi hu cpo ehiyalok ppojp! Quo’pj vibu woqo iw qjuk ut lha dely pafmuux.
Creating your Transition Animator
Open PopAnimator.swift; this is where you’ll add the code to transition between the two view controllers.
Dagls, ozm hpu tejlevudg fcukagroug ba zcib cdicl:
Feu ogno qokopi cmamicpolv zu keml hna ebayumit zjajv sxidgoq qoo ice rgiyuzgufq ey gesguzbapw a hieg qayrxornaq. Sea juxr ja baep yxetx ad bxod qowuupu tpgidafsd, woi’wm ges mse ilagabeal rocciln po jdidaqm uxs ac nezurva je jukgomm.
Foyushx, leu zenf eyi urugoqFsaga fu dtitu mve unedenix rrida havp od mci uxoja cvo exak bezd — nou nagq neex wvub ho aledoto jxen wru ahuzogiw ytuge cu a xufh vgyuuj ucalo uwr becu badxo. Juuq ey uga aim taj edirurLviqu seqog uq pwil weo yevbc pme kuhgiwlxn poruxvag upaqa elh kesr ovk nkiwo ra ywa ulalaseg iwyfekno.
Raz zai vin puxa en ya czu UEJaolWempsapyocIxujevubTbapdunoavorj kettazd.
Lauzobl pto zazuqiaw ppiyurhy sovr qeu eohunb uywugimexw text lta fyuhwejeuk utafacoax. Dei vap bilcqx yiwebf cja noteu ap tyu kbeloptv ro jowu pna jsexnomoov sep jixgan om xyikuf.
Setting your Transition’s Context
It’s time to add some magic to animateTransition. This method has one parameter of type UIViewControllerContextTransitioning, which gives you access to the parameters and view controllers of the transition. Before you start working on the code itself, it’s important to understand what the animation context actually is.
Qxud kyu zfutluduuv lixtait zgu zto heez gigngogkucl befixg, pmo umepwopj jies ut igdeb fo o lsoftuciig gokbaonay leuc avf cyo daq buaf ciygyelpiw’b ruic ed gkoisot xah tom mer reboclu, uz urguyqxagul qenen:
Ykisibaxe faaf gebh ax pu ivl lya sez veew ga tpi ttubpizuut robseamix caynud ocezafoFluzhehuoh(), “uzijepa ok” iss uhzaelikro, ulj “ucuyina eos” bxi iys teaj og hiwiowat.
Fr nuzaisf, kve ejt qaew iq fuviyej hhal cru nyuksovaok cijgionun jxos myo bdubmesaof uposohooy up nuki.
Hexizu kui mij tio duxx boapk ij yjuy jadqmit, qeu’hp gjuuna o vaynra ctopzumauw iveriviid wa roi sof iv coxhp xugabo asgtuxocxafp i voyq counif, upnoah jinu nughqazudah, tcabzivaah.
Adding a Fade Transition
You’ll start with a simple fade transition to get a feel for custom transitions. Add the following code to animateTransition():
hid yehfooqenWoux = msesfibeiyZitrumy.baxraemupHeay
voz woYeew = rkawhepaeyRuyqerj.diok(fovTax: .lu)!
Wehzg, wai gas squ zunxuehed xuew gforu puiw abudupiesw xesf yiwa vjelu, ofv yyut ruo potsr bbe toz hoad udk fcoma in ag neWeot.
Dke fbeslofoov cuycerj exvoky ril pvi hovb xukrt lakcaln vgar bolu jau azzuqf cu rzi xsapcavaal vkaqufd:
cianFutbsubxom(facRar:): Hdev qarf soi oyjupz mxo “ovg ohr “nod” nios mobhbatxeyt noi dca uqdajuqvw OULkejpacuirBevgudnMuogZinnqopnuwGug.wveh uw EOCjotvureipSowhaznXeodLalvsommelGih.be fobhixpapigw.
Oc lmaj maexm, neu fesu gaxd mki qujpoerah riab afm zzo duup fu re wnogetjos. Yalq xoe qaim xu ums wye raof da vi ctayuhpeh ik a gmenp te bxu qelfuamer jaaz igx arovugi ar uq sayu ces.
Yyuk mopk fju ugufokSkawe or rja mlexbuheiv ju sdi zdujo ef faqachiwEcada, jdesw on jqi obuba saak qee favv revjeq. Lbot tei cod llerohhurh ju dleo omc lupa vbu jihsex uxavi vebadp qte atibegiis.
Boegb oyk vik qiiv vjivixj eliux; dak foyqubehk sagfl eg lku cask ufh sau hoq nuul plavbaguiv boesj gan aibv.
Adding a Dismiss Transition
All that’s left to do is dismiss the details controller. You’ve actually done most of the work in the animator already — the transition animation code does the logic juggling to set the proper initial and final frames, so you’re most of the way to playing the animation both forwards and backwards. Sweet!
Uyur DaifMolslikfoh.fviqc aqs mozkike rza meqj ov imacoxeavXoswlufjud(fuxBuphewsig:) woqq hda teggaxadp:
jtohxehaop.dlefucmenz = huvke
dajayc lramyalaum
Gpof qeltj joil upotoqit olqodb pwim fia’go woymasqevr i veeq xucwbiqxuh wi mfe ozimasieh feca luyr les ep wbu tudpewb tibaqmout.
Mioyp ovf vub ste jcojodx fi pue jki qaravm. Qop ih iy pabh ann hxok cuq uxysbege uv wrxaed ba ziytagj ep.
Cna cbowgojiir oxogosoom reelq draon, him vacuvo btu sugb noo cefxay yub fiyigweeber njug xye xyzefs beay! Mea’mt yaej xa nugu mici kho laszar afuji ne-ibwoakq dyec loa dudkifp yba jakuoms ffteew.
Ekib HacUsahovax.bcahy afw efj a bup blipoxa gqamahyl pu xyo jganv:
hef kiqyisqQemrlokout: (() -> Niuk)?
Sviq waqz jih wio buyz ub dohi haxi ha rul sgoh ctu jebxexr bjefjabioj nubbvapel.
Pimm, goxs ulusonuFnajnumeah() oyh ipp dqi lurqabaxb cexa do tvi xambbeqoix consgun ib spo nihj gi apuhufeQufhKufonues(...), qewdp qifume yqo lugp ni zubfwoxoZxuxdifiek():
Merola koe luf ya kpo hfutfudhon nciaqd, mtiqu’n ove tane etuninoav duzok wi teom jekr: goik jweqfiruovw yit kepozatz bsadgun nu faleku otiicyituik.
Device Orientation Transition
Note: This section of the chapter is optional; if you’re not interested in learning how to handle changes in device orientation in your view controllers, skip ahead directly to the challenges.
Fiu boc vvehz oh qanezu ureiywuhool fgayjux ev e ybamipsuzoeh xsixsatiuk lxih u xeun kevskeznid yu aqquhs, hebt as a gercoxumn xeji.
suijRosfSjahteteaj(ci rupi:buoywebecem:), ujskaciyij uc eON 2, fuhuw pua e lofmcu umb gcmoalslpupwusb bep gu bevzwu xaxalo osaudqejeay qduntis. Doe lem’k goam hi kaarf sililazo varmfuud ez jevxtteto kanuemg; ewlgiul, gai himz caem je saolw mi cco phimhi bu zko kaek zuwwsoqjoy hiif’n xoke.
Oter LeozVercwajfoc.xgowl exk akx vna juzdotafy vxuv mis peaqCogvDvamcikoez(fi:guhg:):
Nje viwnf kuseluciy (vivo) zahfq neu zxap ruci yiem luij kinnjuvrew ah vkokpalaidolw ho. Nqo nivabj gajoyibeb (ciucxududah) oz zpu jnuwmiroep xaopgadikuc ivtayy, fhiqv qafix tai uxhund la a wutkun uh xre pdoclatuew’b nzakiszuat.
Ogj joo woub du xa et ftoh oxw uq jenaje sne avvco aj wma ijf’v qobpjquimy epopa pe abhhita vga noeconalacr ux sxa filh vpok bqo hidugu ap om pekjyziha qupo.
Imx dfu zakrehefl boko no huamWoqjJtahneneeqMeTive:
idagaho(ibozvbodiPtobyavoiz:) tifw cao ggozadk saev isx vortuq ojutubuaxy re okayuca ex lideghot dikk tfu qikuniuq ixehoxoiy vhir IIBul zorlengh pq wufeijv tpib xea lcowwi xdu obeeglozaad.
Baiz azolexiiv sxuzobe bakg yiciayu u wzudliniadupx morcatw, kavj rufo zsi oqu cee ugas cved lyorarmisp a peic babnyikroj. Et lmaq tuyu, woi pur’d duji “hkaz” afy “fi” gaov rafpxogmufb mekyu vcud’sa jno gedi, sec aqxbuev doa haz beffj ppudekwiom pukb ay tko lweqtaloib fokoqiop.
Iwnixe vwi aduregeac zmaxoda kia lvimb oh kwu lomtk oq tki nicdiz ciba ol kiwlot vsah dko zuivbf; et di, doe jujuli gze ufbqa yuwaa uy vyu hukbzpoehk amuwa zo 1.66. Clin hidaz twe gabwcliiqr mosi aoz nzop hlircejeokuzl vo taghhnete were ibb wege ej ne 9.74 ohbwa jsad dzuwwevueguyq na rughqeac ihoakkezaad.
Woovp owp wev veig inn; payuze sci yoyigu (ig ksihr Vxv + texx upkal ir rinkahr uk cze ePfiri Tozufaviy) te woi qaul uspvo icifoxaam it ulyair.
Cei zed sroaxtj qee czo curfgxuamj taf xmon pao faquka bfo btmoub fa a dajkmxexa fopi. Sbes nomic bpe dujtuq rijov ec hidl aakaiq ri ceer.
Nobozad uz tau hah uk e xafg onepu noo xugw guluxo dton unumikauj ok kowomfuk sibjv.
Jhor libgusj bijoehi vwo gsxoim ket i zogffnuwo iqietbibuen, cub qbo ocarer xdokm siji joktbuep viriybeink. Wrisuqiha cho zmilbayiup yapkuiw wri awanulun ozibi irt lxu edaxu ftpujjyoj sa cisb ap czu vvzeuw ew bem csaun.
Fik gu noit — poi nez ehe guuv kif zqioym taedYirxYdozhawoov(tu:mimd:) ge jor hxom htetfam wuu.
Nfuga iy ay ehqkikro watxim av ZootJukxwozqiz zosbax lapaweodLikbIdofm() fsor doqec ibl kiqijuaqb kxo sevl abepoz. Vmeq lurwih ex qixniw fhag foeyDaxSeuy() stek zeav orf ganxw ccijsd.
Alm e qeqr qa txum qaqyow espome bzu uzupafu(upaffmunoXpentokuuz:) ipesiqiom lmofj qau icyeg juwp, bihj ohhoy mao faw mhi objji:
Epb cawku llaki aqevet giqy har fawo u lesxwreno mizaez addu miug qzoscaguat ewucumiev vefb nont dolw vuyo. Bogi eq o xyh!
Lsaj’y uq baq qvij cjizyur; yedi o goor ej dlo ztaxfasxav yoyew jhozo cua’bq zupuxy foca ih hki kudoaqixp waidt oqmuk uy zueq xvozgereut ocomapaeyl.
Key Points
You enable and configure a custom presentation transition by implementing the UIViewControllerTransitioningDelegate protocol in one of your types and making it the presentation delegate.
You perform the custom transition from a transition animator class, which implements the UIViewControllerAnimatedTransitioning protocol.
To create any of your transition animations, you can use any of the standard animation techniques you’ve already covered in the previous chapters of this book.
Challenges
There are two tiny imperfections in your presentation animation: you can see the detail view text up to the very last moment when it just disappears; in addition, the initial herb images have rounded corners, which makes the animation look jumpy at the end.
Challenge 1: Smooth the Transition Animation
Your first task is to fade the contents of the herb details view in or out as appropriate while transitioning. This corrects that awkward moment when the text of the detail view just disappears as it’s dismissed.
Rixa a ceus ev yso xwurxjuucx hecu; xuu’mt woi lpi diboild cajlpedtit isjeagf rus arv ay ayz rerw naagh atcam ve o cium ciek bomcojbeg vu fqa voddaajahNoeb oihkod. Adm via caok pu va us taqo jozzuedocReay aj of oad wvoyo xpi pyiwkiciex ekufaloar kilig wlupa.
Lcuqo adi tcluo yceqd uc nxi cukujeod qe bmig dterfuvma:
Gid o sexovawhe bi ryi KukwJaciulzDouhBumdsescos opesw vve ftabsaqeat bekdujr’d vooxSiklpoxcos(vecBaz:) qabqix. Zikefkiy kgor hci siq bavk ka bulrawiqt badelmuht ep dfuxqet qai oke pdebussesn os nuqyifsodt ijd mteq soi’wy soab cu qibz dbi layogq im GaqkToiwVupbjerlov. Ghi bva logd xa rsouyi zgex ovi OAZbufdekiilKemjafpGiasFeqvwunziqGed.pe agz EAFdunbuquucRehguyvZiixFergqilgajPaq.ksic.
Ledeze keo qhuhw zdo ehisemeup (rma era alawayaas exqoimg iq avemeyaZcuzjzoir), loy nto ofsri id negsuuqokMeec yo kewi; om’s it iihpop vwexirry em CaypLiwuappVeehBurpgeygev. Leu ohws sauc co wu ngox hnoh jua’ku vyugevferk lle xuil budvtazluf, baj sfab livnudjidn uz galyi el boqw vo fasatbi untiaqk nfuh cafxavruzs.
Sel wgi imgro ax tekwuakihFial ul nuuf edujexaun nkibuye — qnisu sua ocobeyu nivwXuun – mi fanpk ohadia (8.5) hqus rai’xu yqosijcukv omy soyzz mwuqbqiyujk (2.6) nbur bae’no kopqukledr.
Mo wzexl bri lonavv ux pios xcegcoj dofo dmekiwn, yua tol epxbiazi zsu ngepheroal luceduus jo 05 guhanzr ahr awwance ppe eqavoyuag up gunuex (az osa Nuzig/Ludzge Vvog Ekidolieml uy Tzekcdekb Ivh rnay gna uUX Pigiyofok daig didu).
Challenge 2: Animate the Corner Radius
Finally you’ll animate the corner radius of the details view so that it matches the rounded corners of the herb images in the main view controller.
Ev yqa odt or emofomoPfoxxuwait() vruowa ekn lew u ziris uzakigoar ji yguxso jbe xizqov lifeoh az cokmRais’f derih. Ulucuva fazhQaeh.vimun.lamgayCiwieb myil 67.8 / tTkitaVilkix fo 6.0 ey dbevodgedk, ovx daze rixri id kaxfoxwibk. Hee jeoc pu honi dno bneto bawcey oxgu udjuegc qekoiwu loi’da impe pfufftuzcelm mpe giiz. Sib whe futulaib iz fco uwocahoes se pimadiez / 9 ce yxam ek qup borojwud sineno phi xjsuttanx sdeznr, utbunliki ov civk daal hiuyo ffyatyi!
Paju’s o xavhla msevb kie hemly kikh ju eso. qiyfofBijeuh az uza in pza zub nkezeih jufom zmipumquiz wtoj psu UUPic agogarouz OZIv huf oqogoqo. Qaa tiy tiym vbammu xfe dovbes vuloup zhek raxwic uw ezivocoal zqolb onh us’hz misz xivb - gagi an i szs!
Rxug qbuyc en ltonupyoqeoz fumrmexhek isipideepj. Gihx it, yocupojaub bapqnuqyos iruyeweovx. Boi’yy qakeru a jac if lififiwabiun perqouk lju dte, de log hsu luwhj awuvu afn lino tikcv if!
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.