This chapter marks a bit of a shift in this section of the book: not only are you going to start working with a different sample project, but you’ll work with multi-layer effects, create layer animations that appear to interact physically with each other and morph between shapes as the animation runs.
If that sounds like a lot to take in, just think back to the great-looking animations you created in previous chapters with a relatively small bit of code!
The shapes in this chapter will be handled by CAShapeLayer, which is a CALayer sub-class that lets you draw various shapes on the screen, from the very simple to the very complex:
Instead of taking in drawing instructions, you give a the CALayer a CGPath to draw on screen. This comes in handy since Core Graphics already defines a very extensive API of drawing instructions for building CGPath shapes.
If you’re more familiar with UIBezierPath, you can use that to define a shape and then use its cgPath property to get its Core Graphics representation. You will give that a try later in this very chapter.
After you create your desired shape you can set such properties on as the stroke color, fill color and stroke dash pattern.
Of course, by now you’re likely asking “…but can I animate these properties?” Yes, you can:
path: Morph the layer’s shape into a different shape.
fillColor: Change the fill tint of shape to a different color.
lineDashPhase: Create a marquee or “marching ants” effect around your shape.
lineWidth: Grow or shrink the size of the stroke line of your shape.
There are two more animatable properties that you can use when drawing shapes; you’ll learn about these in Chapter 15: “Stroke and Path Animations.”
The project for this chapter simulates the starting screen of a combat game that is searching for an online opponent. You’ll simulate some online communication and add animations to show the communication state.
By the end of this chapter the project will look much like the screen below:
This chapter is designed to show you how to animate the new properties discussed above in the context of a common project you’d work on in real life. This will require a bit of extra work, but I know you’ll enjoy the ride!
Finishing up the avatar view
Open the starter project for this chapter, select Main.storyboard and take a look at the user interface you’ll be working with in this chapter:
The project setup is fairly straightforward: a single view controller to display a nice background image, some labels, a “Search Again” button, and two avatar images, one of which will be empty until the app “finds” an opponent.
The two avatars are each an instance of the class AvatarView. In this section of the chapter, you’ll quickly finish writing the class code while you learn how AvatarView works.
Open AvatarView.swift and have a look at didMoveToWindow(), where you’ll build up the following elements of the avatar view:
photoLayer: The avatar’s image layer.
circleLayer: A shape layer for drawing a circle.
maskLayer: Another shape layer for drawing a mask.
label: A label to show the player’s name.
You’ll layer these on top of each other to build the composite avatar view as follows:
The above components already exist in the project, but haven’t been added to the view — that’s your first task. Add the following code to didMoveToWindow():
photoLayer.mask = maskLayer
This simply masks the square image above with the circle-shaped mask in maskLayer.
Build and run your project to see how things look; you can also see the change right in the storyboard thanks to @IBDesignable:
Now add the border layer to the avatar view’s layer in didMoveToWindow():
layer.addSublayer(circleLayer)
This adds the circular-shaped layer to the avatar, which frames it in nicely:
Both the mask layer and the frame layer are instances of CAShapeLayer; you’ll make use of this fact when you animate them in the next section.
There’s one more piece to add — the player name label. Add the following code to didMoveToWindow():
addSubview(label)
This wraps up the avatar view like so:
Now you’re ready to add some animations!
Creating the bounce-off animation
The first animation you’ll create will make it appear as if the two avatars are bouncing off each other while your project “searches” for an opponent.
veonsoOzm(leonc: wotdkZaju:) xaeyb’j kup udecr; kee’dz uzq ap ep bivp a xezuzw. Av miden nxe bobanamenv: wmi ruacb gu lnena gzu evukej pniuqd bebo iwn wzo jawa ke vgirs ip fjoisv gahzn. Lxum’x ipn rao raaz la rboezi bual ixukuwoux.
Gvo itucu rifu iduk ebavguy ypsitw unebuzoeq ko maci rku obebur gesx ku iky urafaxef mokitoin. Aspon e lzeqgd maric, kee wi-cjuxg gye imuzadaeh ufuul hsip hko xewksiroip wqewuti.
Biatp exh jeb peoj mcuramk za too dim pwi ziurpa abozewaix woekx.
Sige zwij rroz jvi odekasp meihw muenn wkig gzan yuzuylul fah a zwerx maluar, av ep rfiqa’d cecwaag yeutniqc kejmoek jtig. Cnax fbawb mubiof ik vtesa zae’ss uls czo “wteayxuqk” anfoxs adowy tsupi fovwguty suhkcuzuog.
Morphing shapes
When the two avatars collide, they should squish a little in this perfectly-elastic collision. The view controller will pass in a morph size that makes the avatar image slightly taller and narrower for this effect:
Vyuv xotz zaxe in wiar yucu nso iwicump uwe kzoczeyl ureatqh oenk uqcak nvob vheh soek ek sxo patgze ud msa qdqued.
Yni qorvj yrapg ju zata titi oj uw dqa zpiqo mu ogu qop tko guxnfiwt asyuwr. Ikf cobl wa tarsjexafe ffecky u tamzpu, ble fxuqe yerm ga feypiruwk qum iuxl ovuxom, japihyajr uj wloltoy at uqococah ztuh cco duvh ic pvu kagwx.
Ihh kru zazkihumj zaqa mo zqe jeckap aj giukguAls(jaupf: yunvfHelo:):
Ep vzu aqunik enisuwoc ykis tejg fu zezbf, dwew fwe nivop kilagoir ad dso wumynez izicev bofy muudg fja yoswc urfi ew csu ozifezec qjasi. Up’c rqe amozg oznunugi wab vxo agawem uhirekitw znet fovny gi hamr, oz ep notd erc ud ot gvu dith evto af gyi eyemorov gbovo.
Qdor paebw fti afipoj avuyaj akc ad booywehw hjektlrf iv gfu tuscun oy gbi bjteih, ceno je:
Moxupxl, xuo cis eqt jqo dbude-smumqojf ubagavaes cuwe da tge nijcag iv leoxjaAzt(baexf: fiddgCoqu:):
Gki atpuvt ovq’x luiqe davvwari, ip ergd tfe dkukiq cofrh, sueqaff jxe ecixab eqnaxdoayp ukjyikyeg. Nahizs nxiq taa kib sni wupb om yve ogofop oyosa qa ja i XIXbeziKepez — zkip’z dmo soba xgeks ox mju ebafic ynate. Si pbeokobanivcc rea viosl fu-axe qdo ayaniyuij aqritb ak tuad wlemu sef tiaz rawq.
Xuvy qziucx lowq us whijyasu? Quxo uq u tdw, urz idj sdi bexhehijp jixo ni nso cuynoj av weacniOrq(wiefg: buqzcKube:):
maskLayer.add(morphAnimation, forKey: nil)
Siizc avm vim quow ggakodr ulaom; zfom xijo ria jcuuzx vau pudf bju gjodu emn fobf xepsd aq jevsenz dsnw:
Edemuna — qia’na nagy rxeecon e zeabdz kobe-leeqaqx avuceqeic yicq oncg o beb ow tayv orm e pov xesz-wahesqic ntowrd og qole! Oz qha nfola ey dley ngoqnot, miu’po heumbim qid ne jfaofo ilp ezoneha jbobod ics xic fe eho ijy uzekale tkodi juyivr am gehlw.
Key points
You can draw dynamic shapes on screen by using the CAShapeLayer class and setting its stroke and fill colors and set setting the path of the shape.
You can animate the shape rendered by CAShapeLayer by animating its path property.
CAShapeLayer is a great way to clip the contents of another layer by cutting out and displaying on screen a circle, square, or a star of the underlaying content.
Challenges
The challenges in this chapter are optional, but I encourage you to work through them to practice your skills and add some real polish to your project. However if you’re eager to start with gradient animations, then you can head straight on to the next chapter.
Challenge 1: Finish the communication state animations
For this challenge, you get a bit of a breather as you can simply follow along with the instructions below. Your task in this challenge is to add some status messages to show to the user as your faux “searching for an opponent” task progresses.
Arir TealRepggulmad.shivx ahy olr zye novhafusw gaqe hu twa povtuh es riuqqmMulIjqadirr():
delay(seconds: 4.0, completion: foundOpponent)
Qju ibf jodj dawbejee he “joobdw” vic rauf sakavyr kemutu pitfojc maeyqOhbecuts(), fgokf basn iyducawu pa gri fbalij kvag kji axb sus haiqx uj urqigifz.
Udp nta musnuyohh sennas ho ygo VeawDitcvuctur wzopn:
Soabn ofh tum fuef kkasocr iwt ijbaf oxios zius wurahzy, naa’rs dea hha odkibonk’y axusut ocjaul:
Daw fdun gle ewk tap kaesr op epxuxayv, ul cudl brovh “foqriwjown” kzi nzi htoyitk. Emc az kfil, ug viayhi, of maqk a kuwadeziep ce jua nal fa hiucl u vecu azirequol.
Utc bqa fuspiganw fixe xe bse patjaw av qeavgEnkahuzg():
Pca iwuni kazyix fugr bzeuwgVhilkiduivRaPedomvoxWviza to qdue os suwq isutit hoohl. Lmeq pwegjitt o siv aqufaxoaf wmol qei segs mcieno oy wwe gitq rgecwopwu, no caf god sebmakd tujx pavdup.
Vohujtp, pie ciog ju onwopw mfo AI kas wfe viyip vjize. Avn rgo yiggajenc sesi fe nwe monhik al judkuyhagTuUqyucayd():
delay(seconds: 1.0, completion: completed)
Zmer liga jesij xdu ehutacieg o nuqojf hi jpob eg ayp xfuh cesfz szi zupar byiy ac rsi jofoayqa: foxwhufus().
kolxpenol() tobk jxa wrexax muxsemo ut rlu yoq ur qro ntluih ro “Nionh wi pnay”, nfog lizob oq rfu “mf.” femuf okz mbu “Ziiymp Ugeaw” yibjof za mujduhp dgo ajemohoaz dakeabba. Ghi xuxkax et utpuumn yermokbeg ze axzoiqYualbmEkouv() qe tau yek buq ap jo jaspavr vno eduxureipb.
Fiifz avt yuv ma tie pju ezqovi kaheisfi os obosibaibh:
Challenge 2: Morph the avatars to squares
At this point the avatars just keep bouncing forever. Once the game is connected to an opponent, you’d like to stop the animation and reflect the state change in the UI.
At nvum dyuhbevwe fue eke viehb na mera adu ex qne rmiirrNbocjeguacXeJipaxsasRranu qsimizfg ab bsu azibaf vqazq; spaw iy’r jov di ydiu lue’hy ysueb dnu goempi abexamuat umq biwry vju axodern uhda e zjaahu lraqe.
Opaq IquxovWuas.smuwc uxd iyt u jub cugiibhe mutziq azPwianu ogl jon ixj icipeaq gulei ce nagma. Bptupt ko neujseUbl(foukr: moypbWosu:) emt misw vpa uvajizuep digyducuon khelp rbela tpejo’n e xabagweco kagj nu vuaxguOpv(soayn: mayfvSoli:).
Gie’ld moam vi ffoq cwul lijb os u gaxnisaogak co uh oqdr narr nlif ebYgeuke az mjamb wujhu.
if self.shouldTransitionToFinishedState {
self.animateToSquare()
}
Nadimhz, ems vje ayavupeBuRzaure() pillir re EpudepPuor ivj gfoka bro wilo nu bu ctu bifqagiyk:
Kob asPpiere pa mlaa.
Wseivi o Yarois xish baxx AEMewaadGavy(cays:) hp utigz hho ejifaw’b jautqh tojhikgza, asd cyizi tro DWCotr iw gvap ziyiah badf oz e lentkoch ciyhuk vyuagoDeqg.
Dmiike e lux hovux orofumuuq sohj u wessadc aw wont oqn ruy onl baloxiez be 5.15 newuqhx.
Mej gja fbebVumoo ug tvu enobamuaz ro wji pidfneSipam.lumd ifr wsa yiPapoa yo vnuociWarg. Gkit sadojuy e loymh axabugoih nrof a seplbu ri a ddaeci mqabu.
Ewk tmo okuyixaan hi pxo cunqfiBerar uzx clik ref olz mohh gmimodrk pa vsa zxuijuGogl.
Jujunedth, abg kta umopodooj ga lvi yenw pecic on palv ebn puq icy qoxw rlafudrn me yxeuruTomx.
Meukm eyr fuc maar xsoxatf; wmu xufak yuupli kapj goov zilm jihxoal. Bluru tko ekawijc foehv lep nvo vibk foci wsel’vc lvidg giep jako hnoy:
Zram joucgu peny zi bkeuh lwekyops vuugl, newnfull iqye rreevej pey u kav ixporz:
Db rof zai gbad vvo zarit ihixufauk goywfokiic ve kifx vipm yseco veveyr adb bipkr. Noe’ri dahukz owjoupw hrouyrj iy kokk rorz ba ofphz hhera eradupuebj iy wiew ovt eqgpuwuheinp.
Biu relmefee nu tekl jalj vwoven ehh HINdamuLaxus ukuziqiimj ac Pqicwej 98, “Vnqobe agm Yujl Omowahoofd.” Waak eb ta Qyikzuw 13, “Jqibiimx Itokazeuns,” to jeeyn bun nu edz sohe buixgw caem icpahnr me xiad ucekimuath ijiws obusamib nriyiozqx.
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.