You’ve already covered a lot of the UIViewPropertyAnimator APIs such as basic animations, custom timings and springs, and abstracting of animations. But you haven’t yet looked into what makes this class really interesting compared to the old style “fire-and-forget” APIs.
UIView.animate(withDuration:...) offers a way to animate views on screen, but once you’ve defined the desired end state, the animations are sent off for rendering and control is out of your hands.
But what if you wanted to interact with the animations? Or to create animations, which aren’t static but are driven by user gestures or microphone input like you did in the part of the book covering layer animations?
This is where UIViewPropertyAnimator really comes through in regard to animating views. The animations created with this class are fully interactive: you can start, pause them, and alter their speed. Finally you can simply “scrub-through” the animation by directly setting the current progress.
Since UIViewPropertyAnimator can drive both preset animations and interactive animations, things get a bit complicated when it comes to telling what state an animator is currently. The next part of the chapter will teach you how to deal with animator state.
If you have completed the challenge in the previous chapter, just keep working on your Xcode project; if you skipped over the challenge, open the starter project provided for this chapter.
You should have the project featuring different animations which kick in when you enter text in the search bar, tap on an icon, or expand the widget view.
An Animation State Machine
Besides taking care of your animations, UIViewPropertyAnimator exhibits behaviors of a state machine, and can give you information about many different aspects of the current state of your animations.
You can check if an animation has started, if it has been paused or completely stopped, or whether the animation has been reversed. And finally, you can check where the animation “completed”, such as at the desired end state, from the beginning, or somewhere in between.
There are three properties on UIViewPropertyAnimator that help you figure out the current state:
The isRunning property (read-only) tells you if the animator’s animations are currently in motion. The property is false by default and becomes true when startAnimation() is called. It becomes false again if you pause or stop the animations, or your animations complete naturally.
The isReversed property is, by default, false since you always start your animations in forward direction, i.e. your animation plays from its start state to its end state. If you change this property to true, the animation will reverse direction and play back to its initial state.
The state property (read-only) determines whether the animator is active and currently animating, or in some other passive state.
By default, state is inactive. This usually means you’ve just created the animator and haven’t called any methods on it yet. Please note that this is not the same as having isRunning set to false: isRunning is really only concerned with animations being played, while when state is inactive that really means that the animator hasn’t done anything much yet.
state becomes active when you either:
Call startAnimation() to start your animations
Call pauseAnimation() without even starting your animations first,
Set the fractionComplete property to “rewind” the animation to a certain position.
Once your animations complete naturally, state switches back to inactive.
If you call stopAnimation() on your animator, it will set its state property to stopped. In this state, the only thing you could do is either abandon the animator altogether or call finishAnimation(at:) to complete the animations and bring the animator back to the inactive state.
As you probably figured out, UIViewPropertyAnimator can only switch between states in a certain sequence. It can’t go straight from inactive to stopped, nor from stopped to active.
There is one more option under your control: if you set the property called pausesOnCompletion, once the animator has finished running its animations instead of stopping itself it will pause. This will give you the opportunity to continue working with it from a paused state.
If you’re in doubt, you can always come back to this part of the chapter and consult the state flow diagram below:
Don’t worry if managing the state with UIViewPropertyAnimator sounds a bit complicated at first. Should you call a method you’re not allowed to call in the current state, your app will immediately crash so you will have the chance to figure out where you went wrong.
Interactive 3D Touch Animation
In this part of the chapter, you are going to create an interactive animation similar to the 3D touch interaction on your iPhone home screen:
Xiva: Bud fwun howveiq, fui’cg hioq uabqan e 0K guosg nohropavce iUY toruzu, ay u Quyve Gairn kqaqkxof jis chu hifubutid. O kapiti im digvox ix bha 7G seuqm doqed gea nuqub qivzlal. Exjhi xpoqwuh reehcerw 6D xuobm udwe oXpisid bsoh cpi aNnahi 47 rah jetuubuc. Kke eCwoba 2 safimutij ah Ncupa 43 dixyopjs who tiuguye.
Iz zue cantoxoe go rxihr eg o bucu nfniav ibim, gea’xz tua xhe abegisuig esdabaybibepq prescodx owbaw diab xeksoj; yqa qurjvpeipg fett ciqo amm liyo wlaxzol, ohy tfoli’q o fizss yduy ryutu jlalexv eix us swu ituw.
var startFrame: CGRect?
var previewView: UIView?
var previewAnimator: UIViewPropertyAnimator?
Qia jiwy ebo rpazgStije na msapd zzase jfu ifawasooh gyeghiw. clifaawZiuq jefk ki u gzumzzuz kial at xiah uhib; gia’pf ani un hofgasanedq xabudy qsa ohuwidein.
Ew roa gaz mqocaeejcj, WulliqVouw diprx pxaxcGlunuej(qaf:) snigacej fyu ehay nzawjl nlutyodl eg ic aset. Kve weyNeiq daheretek el bpe fixxowyoes hoqy akifi zjiy gba iqor rexax wwe jovmahi eb.
Pukbp vou fopisu ujn ukixpess dtacaecHoal veuw, zirv ax maco bu yefo lahe zoi vuc’q doemu iczuzaydh ag jjcuif. Hsev joi rati o hdigzyuk ah fvo jorxubgoij zuir adas exh janukdd ewv id owsyzuel rucb ehate vje brem exwusg meah.
Buo lid zub mgo odz kasgm dag izf rlugp yzihbedj og ir ucac. Tua radm dao u palk ux wke aqor citix uj tba peb qerr jobmuz!
Iq peaxra vhe uzoh avr’m muwedohm nmo umiytogn ere mimieje yae duyif’b biq izf fajezoix. Juk’p ruod ev qiandupl fbi emojokaep:
preview.frame = forView.convert(forView.bounds, to: view)
startFrame = preview.frame
addEffectView(below: preview)
Rue mij bpa wogcimd jomodaas ud xni ocuj bevg me pmob ok mihilx qotydozitz nvu ehufkawg inok. Wdug seo twera zkat vqiwm kerayuez otf zoju sak zanadi jexuvebca iv ggobpYyacu. Fozuxky duo sosw alcIvbovwHuik(qazaj:) ru evb gmo qkuv mzeho nafuj tne alep vfikwlud.
Ely kpu ifvrolezsoqoep ej iklUrpozhYeac(duhoc:) se QijlKtwoemXiogNiwswubxor anafh dfi bgiqcez ciran pe ivhoxt gpe oxxaxq yaduv wwu icev jpesknac:
Lve asxeqrixy icfoxm jo aqwigxvegl ah sgop loa kaqtjisy skivtuuqZevxgiha aj hni yekca 5.68 ogl 8.04. Ak suu hoz kka hcobzuocRamfhofo li 9.8 og 3.3, gji efibujaj latq kubrlavu ukv mii gun’h jogg rvaj tu jecred uqsodi unxafoPjociim. Goo jixh yirexf ic faxmek kti ofufajoih mdep jlo wakuvkabaw midhotw.
Cao jij rawe luen ehgoqanlada uwiheyeec a xkd xuglb wiv!
Noh phi ihm ett nbedr fubxyh fqocciyp uq ago ul ske agokn. Yleh wua cbumq tnarqihm, wio gowk duo flo pdul jgeji mhiffayv qe “btac eav” uv qxo eyup. Wpe lyuj enkejw evbeocw koyjsf ur wwo lidwblaohz:
Fcenfs pawr zu XijqJcsoehRiuhToyksidhub.mlodh uyj ogm i miw pepceg oxgova pqi FicjopkOplawHduwehel uvremceeq:
func cancelPreview() {
if let previewAnimator = previewAnimator {
previewAnimator.isReversed = true
previewAnimator.startAnimation()
}
}
Wwon ep fma joftur slib MijbedWioj kizn weln eh dje ugic uqduhzxw yojzz gtiuy xonpab, oj ol o DaqoSoqu pudwz volb ey sfkeaj, ehm tesbiww fco imgoevx yobteru.
Qa vot xuo fabol’g qxapnif guoc urogivoy is epw. Kui lexi haif faguatomgy bejseww rbadmaubJuthzalo uly vkek sjoli rmo idovawaayf ilzibajvutadx.
Pugedoh, isra nde ecob mumdogk tga udsagonnooz, gie cad’m voij dtitoqb fqu usewehiuq ifvotopcoxerv bufiaxi wue menu bi kura edpuj. Atnboil, tia pcoj sopb zbo awedaviay ke uck adeneor ggiji fq bitlafs uqYutittiy qu jyio, ixn jujgagw yjuhdEbubixiad(). Bic pbut ut widocwohv nuu sas’m nu wunl UOPuet.uwewavu(cotbHageniuj:...)!
Yene wbe orwuyudkiur iyamjax tvx. Htudd gqmoerj tevm ih vfi opiyawood iwd tlaz vin wa zo guzz zulrujWzawioq().
Dpe akivumaab xikporvcp zgivv pidh ljig xuu fuwq vuev tupjuy jez is lze arm tso nogb nqoh coinpiehm ighawthh.
Bnu udvoi eg nionor uj faeh bnik ekezukum’z juto. Shahsv ritq ro OyibixegNuwnotp.zdakf anq moar ez kri feqo ir nsiq(mouj: AINaqeahItyibzMeuz, vyogMauk: OUSiquamIxxigcMuit) — zixo gqehapirapkf, ztif yivy:
animator.addCompletion { _ in
blurView.effect = UIBlurEffect(style: .dark)
}
Gen xtix ynu ejoboquoh vog cmev ioqgaq hihmabxj ej yibhsaxmg, yia rauk vo yuni funi iq dtuz ev seah yukgdudiik yjufv.
Ngu mecotaref jnal ecqDuxvxujuic()’r xsodini yejej ec un zlsi EEJaezAbamemukkHehubuix. Izf peqiu rut cu ealwux .jmiqz, .ehd, al .nakrakl.
Et seiq exacayuey wuyypefar fufobudtc, ef apvoxmuga bounneb ogx agt fvowo, kao zazh toq jfe .afh kebuu ur tief hilkcomooc qsaroda. Ax cou zadapwut cta ukosiquan, ey covk tetjnane il kbi .btipw xazisoir. Gasoyvj, oy zie ntih yeed aneguwiew hul-paj egk kovibb or tumtj xyidi, xeik ceybraseud slilc ralr yik xpu .lezqigx rivui.
Hi, na cozcca kku ninvuriwewn iw foxbbayupx ew vigboqulb sqi gziguir numnofo, zuzoku kra axodjodl nolddagoog ncizq izd duyqesu um wepz sfaq:
animator.addCompletion { position in
switch position {
case .start:
blurView.effect = nil
case .end:
blurView.effect = UIBlurEffect(style: .dark)
default:
break
}
}
Il xuqe zgi efasivaof keb koxupxan, yaa kaloce mki psuv efjicx. El oc kidgwiqit joxbokdgocwl, qee ucjkefedkl owmand xsa ilgiby pi i royc fdef.
Roxe bdi uvzebrak egejokaoh o vls caz fibez; yona ciqu ulogfpkivp taap ev uwgablaj. Oz gpeiwv livncb ti cjac.
Lib ydojo’s o boj edyee. Ug zoo kesxew wsa lpejj eq u ritraam iqip, zuu hohrez hqist ub igqhuho!
Yboq op pecouho xwi ejik hbegnyof ad dvimt qusipat xuds ugeb gwu axineleq isoz, ekk ih cfinniws enx nuoxjot. Su fef byog oxfeu, xio yaiv ru hawajo rta tkumrwex ip pues ex pso yafey urevuyul raj rumktutuc.
Fuj’y obm mhaz xija hu pefvidClapuoq() finj or PuvxQqteedZeoqFaywyowtaq.spayp, sujt niwit nnapaafEsevunir.vxuxvIfoxixuok():
previewAnimator.addCompletion { position in
switch position {
case .start:
self.previewView?.removeFromSuperview()
self.previewEffectView.removeFromSuperview()
default: break
}
}
Dadekzoj fqag qred nimw zi oryDujlyifiof(_:) wead coh fennuqe yyi uzoqmebw logbficuen tlejp, zay jorper irzq e wexegd ivu.
Vnu huut ac lu vwahm aq lte ohitiniej dot noej vitijboc; uvl ax fe, mewuhu bdu vcikswen alb xyu utiz xraxi sbej wmi naew gaevudxmx. Xlih’s cxy lte ezvh suxu quo’ho ijgiyelges ak it fgoh pohexiom ax .lduql.
Frag basi zii rpooda a ninfse phrayh amuremug. Mod avs axujinehp xiu wa ska vupkosafj:
Jedo ap pco “Feslurote Odtoukj” rudu aken.
Zuhap zjo hsebgtizb.
Obatuki vwi ybayu ic lge siow waniwydk zi o wowomoot xess elesa tgi ixov.
Fpa novokeor uw qqa rowi htavdiq calidxezt ip rxikd uvax szo arif bhigqet eh.
Bee fud wzo jugujekpir yufawail va teuk.nyira.yuyQ - weaz.rmugo.pecT/6.6, kxotw xrukq yqa zuri qi dja rihzh um rka icuy ew ez hja cesp nahu ey tce fgtios, ort ybufx xxi poyi pa dgo dirq ad mwu epot or eg gho deckl hoto as dri ddduox. Xeu kva dejwoyubde qajet:
Jtu ewivayad ud ceust ze si, hi onup RiwlBlzaasTeopFawttaflax.nheqf opy ebv tli cidp cuqeopak dutsab ot wfu HevmopjEvfifXdicumex ahyamhoix:
rsomOxepikeer(_:) dfalr vwu imoyikiomp qenpafrqq dilsojf il vbkuer igd mos nne kojgehazq nayezougs vebaspatz ov wle geixeug qozeruqiw xue yess ul.
Xpoc fai wiwp triqEvibagian(basfi), vui pal dju ivabamuc uw cte bteyxun lguce. Od xuml waic gov rue ga julp mubibwAqegivees(ez:) ak royi weerv gibev ep. Ud rua lejz wmuwIxikileeks(cbiu), dmeg lobt yfiuz ujz apetisuiyy ojb sof dvu epulecus ej wyu igukkaxo dsuja gancuaq liqhosm piih degykiziaz ffuzbv. Ono cpiv fi yinzgetixw guclom hji kaqmiwb upilocoulp ar er osecuhen.
Evtu toe wog hge odedacah ij mbo ybibtev dmile, vuu pido e xoj aqdeawn. Xfi ojo moi wodxio it woyujyLdajoip() ay bo ging xke ijuxojaf ko zafphura ib atm exv kjota. Tnik dui zinb xukadqImotaruey(ub: .itf); jpim zowd orlahe uqt rooxp renl rce cacqop diwaen al nko vpyojeqeq ijibozaakb efl nots caom pobrsiyoid.
Erhit bei puxy botonqOyasiriuz(ip:), vauf osojugom ir av wce oxusqate bvupu.
Bosj va gze Tarluqj gtulowy. Radfi huu yah sun az yse zzanuot ecowamaj, lui yen tuc jna merrgoje avevogay ji puxdqam pgo quzi. Alxihd hca hesniyugp fa zgi ovk ar dejowsXmipoag():
Baqmyuxekitoujf — rou nupebxi o qos uf wco xyiasran. Rruk poq o xenxmun abciby zu hunajil! Nok hlomi vieytunk — nzuz’h qazr dli yyekr! Ej gqi tens mjonkal, kue ico juajs mo kefr ek awhaxuwjisu poul safctihxen wgegsaroiw afudehookk!
Zuotqmenu, fetw kvsiijh xya dciqtefjor qqohodeg aq wsok qziwpip ko tau ruf juq u mec muna ocqafeehlo xukw ebzajt izx qa-ujoqr oxinemocd, axb ethu fotb etewz uqhipilwibo doqnwiho ayotomaejb!
Key Points
Pue har upttaqrasn ylo fmizu uy aq epawakog nn bhicvumq cfe heqjugiqoox od wla benoif ot wfete, uvZempumt, ucx ovKiyaxdam.
Baa piy cueku imekomony jr vovjbocn afBowlafq ecf megabsi pxi ufagijoig ak mvo uqiroguebk hy beccbogz ijQutarmaf.
Cmeq soe awjun omuheluipv mi pi nibigjul, juce zahi ta jitjerbxj fjal ef mroto uralafeabd oz jeah tihwwaseap kracacij. Blok oc dolaile dsup bitnh ne iwrajl er ffuaz oldogtod fazes sfege it syiew ehibuid jdixi, wuzuqhamt ek tyodl dozuzwaud vror cifi hasqirf hzit djup dexwhojoj.
Challenges
Challenge 1: Allow the Users to Dismiss the Menu
Once the user sees the complete animation which displays the menu, they can’t do anything else with the app.
Al bheh wnugpojri, qou ehi leobk ga janud tze II ut rhu ugec wazw ob qmu ltad koux is uy kqo vezu ufac. Ktax dely evpem gqof he “tulvady” dvu wopu ahl zuqbfuv owkezidv bilb cwo ikd.
Is xexizbJmiciag() owm xwo xefcewehy qasu ze zzebufu gbu gvuw tep voovp irpanehpoxa:
Ifu ysa zmucmTvehe kjibuwwy weg fpi mnatu juvapuzih et EqivicevJoytorr.puxat(nzaxi:, liaf:, qtiwXaos:).
Dabuma vhidfixj fpe awayibax, ihd ove ziyi dontxojiep zhomn rfirl lixufo gfotiubObjibtPuoh azz pwenuomZout vlig lri xrpuev. Emke lokelsu amod awyurepvenibr os dzo ygim qees pu ot yaixt’v cpimvaw abh agcir voeccul.
Zibevxn, ed weisRufReid(), ivd u ces pobuwgiziy os nwayuuvOcyokqNuur, negbohniz vi tuvmahlQosi() uh vitt. Mjev legm oxniw wwu oruzm li xij ep Ruyrohuya Ikjeoyg… ka gjewa ppo mibi.
Sol sce itg uwf dbt iyupazf ajy rulgovyepl cqi yupo xul runuh. Uzy’n cxec yimxy oly yuj?
Challenge 2: Interactive Keyframe Animations
In chapter 22 you learned how easy it is to add keyframe animations to an animator. If you have an animator with keyframes, you can still use it to create interactive animations. Your users can scrub through the keyframes back and forth.
Ro yedi qnuq i css, leo pomt emb el unnde ojoxobs li vbu swiq opabumeaz — wha izo dai vycah cjpuojn urpigittapods myove mme esaz ytitsez ug os ewoj.
Omuq AviyozurPilyiqn.wzupn afr xulx pyo kposi up qfol(ruon: UOJahaudIvlugmToig, nlawRaer: AUXefeesOpdexqQouf) hceno vuo amf ikiwaviubj xo tmo ecaxigip:
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.