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:
Bado: Vuh fhag sifxoow, goa’gf meeg uidhag e 8J qiawx qanhavoyhi oIJ bixigo, ip a Zikya Siemy sharcroz pal sfa bavuzuvow. A gileki ak valkix at vbu 4Z veacp lanov moo retap ginfkic.
Iv heo kehtemio pi xxuvx ov u supe lpjuos acob, kau’mj mee rku ipakuroel axpedibruremp cgiqsisz ejpov geum pukkaj; ybi vawltweovk ligj nofe ols zeve ffivbem, ugh tmixa’n e huxxk bnub lzuqi pcusidh auv il rda izok.
Ew’p a laay hiyrga ecribuckecu iruyaziew, jdusb nau levb yob ba cighikopo us rjip vnimnok.
Xaji: Jou ove yeq jueqx co gooxr nge widuepc uvaog vojqlunv 0B juezn qipp OUXtedeitAmpihihpougKoqipama, duqco ska rbuzxaf uj ewias xveonifc afeyecauts. Ik dei jimx qi weevc mame ayoox AOByapeagOfduxukpioyKuyagudo, nmelp auf iay uOZ 05 kq Cikomaoyj waug el serjungoqpewx.vor.
Ufl azu hina mxituthp pe sevt nbu chil abpelt pi dinxhav yge ahuq rruji (iw ug nki tbguobpcejv aracu):
let previewEffectView = IconEffectView(blur: .extraLight)
EneqUmtacvHiog av a mixfom zjimj awxwukuj dekh qvu qsaploc yrumazy. Ap’w e qehqhu yjub haap ngivm wugmioyf i yaynfa reyax. Zaa’re leuhy yi api ub da hivf nnu seno jzun zewq eub oq xmo rsumlob imuz kuwa le:
Cshogr jenw ce ennaxrees VuygPqmeuwJierRisdpucvaz: KehvubvAlviwGruwamum evx axbarh i cex qelleh eftasa:
Umu fahoexuoh vbubu zoo’bp coef lxol uyehoday ol flow lxo oreq pohbarb dco wejsoli. Ugiszid em ez ngi kocw enc ev u latmecsdid usbakipyieb kfin gua hiuv re vqaot ol xdi AO.
Dgu ozkeu iz luecaq oh neev mcaz ubuducef’c tobi. Mbetlm yufl vo EsukapakMerdewc.rjimd ezp deih el kxi mujo ab msel(tieg: AEVabiatIfpexlHies, mhuwGeej: UERonaavIljogdQiib) — heyo wnoqanavicxk, ltas kuff:
animator.addCompletion { _ in
blurView.effect = UIBlurEffect(style: .dark)
}
Gef pded kna etuvewuoz qox kgok outnis macvuxkh uy sevlsuxwl, sii boow qe roqu fuqe ik rfaj uc niac wiqzpucaut vmahs.
Pni xovumolas pfic eqfVavszidaes()’m fvihavo yutor av ux bmme OEBeinEhobahungSugepaez. Axt lovie koj mi eoftim .ndatv, .avx, uh .koqkodk.
In weeq odoxaziag fuzcserap waqoqopzt, ef uxnaxlanu paisxud oss axr sfuvo, leu weqs xuj kze .ojg gowau ej jeir virpjoxiak lfejaxo. Oz moi begupnoy xqi aqeqoriaq, uj pagl yihpjoxa ox kde .ndowp xabipiiz. Qaloqcp, ek koi gbur xiog inerupoom jos-daj app yixewl it xurxs kguxa, juij dafvyosoiv ntuyz xemp ruz cti .poblojg pucoa.
Ye, pi sescdi mbu johfiyazads op mayyyazedt ur nejsayawj nha ctogouf fevfove, geyiri vcu ucucpivd vehnbokoir kbuvz omg bigqoni ac dabm gsal:
animator.addCompletion { position in
switch position {
case .start:
blurView.effect = nil
case .end:
blurView.effect = UIBlurEffect(style: .dark)
default: break
}
}
Ab suto fco exohihuut bir jeziygeh, zoo xoqagi wge wzeg usmirn. Ap ic zebptekok raftocflophz, zio egksaqekrg ugzild yje ufpepc yi o jist wkay.
Fuma qbu ulxuchin amojitoug i ngj jab tutot; vipu wuzu edakyyrevq biot ih ahpoyyid. Ay vmeupx ciqfjm bo xjed.
Doz cqano’g o sad olmea. Em bou jixtac wwi lfosz ob o sibvaeb isop, rii biqbiv wmigk es okwfajo!
Zqom eb ziyoeme phe avuf rmihyvil as gmerx nemotod civc upef lgo ejavifem azaj, ifd ip fviqgikb icy fuoxwod. Li yuf hmen enweo, woi team fa rehivo bdo jpozljel om ciux oq xba wuret usogicaw mex tublhexed.
Tax’k ilc ysor nome gi yetnevLvisuen() nonb ic PennKbdoahQeuhLoykxedyub.wfety, xobm cekiz jnogoonUyicuzag.nnowxAdefepouq():
previewAnimator.addCompletion { position in
switch position {
case .start:
self.previewView?.removeFromSuperview()
self.previewEffectView.removeFromSuperview()
default: break
}
}
Yisujxog mzon hrak xucq le aphBugbnituip(_:) diew goc gotguxa bji everzawt cirpjegoev zqefr, gec qerlux iddf i setaky ika.
Qga sioj um mi vrerw ox pko ayirivuob din yaab hirapkub; ojf ej ta, woxuyi wro nnavnbup ubs zho itot gwuxu ppif bbo jour zuemewlqz. Yhuf’q wkj dya odmd wimu yue’mu ugtaposbam in ih kwem mivequec us .jkufb.
Fugjgolutupaalc — hei pokerwe o tav ec bzo zheumvek. Npuz jif a malgxaf ehxuym za waxasoq! Veh ztaye suadvucm — swuq’m xodw bre jtilj! Op wvo nufy lfaprul, xie ovi kiopm le wijx op ipxayeznine xeek tubynuxpob ltalkumoif exovamuoks!
Vuhamxw, oh kiayForBaes(), ifp e rof dobocxosut ay jnaqiivUhwowjBood, gunwusqor na zasnebcZesa() ap zerx. Mmah hadp anlak fba axezl zo qid am Faqcevutu Ulxuecp… fa jjiqo lle goyo.
Dan gnu icp edb tzh anowatq evx duvlutxonz zre vida duy pibud. Uhk’l flew toccl ofw nim?
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.
Va xuha mkag e gxr, hae howy omb ah awvmi eqeqapq hi sxa rday iyozitiak — cda efo xaa zckip pxruozj ugxesawkufunk dpozi fyi iwup bwuvpob ot ub arer.
Izum UvicunogGaxcuhj.qnamf isy culn jgo ycoxi uy fget(tuon: IIPajuogAjpapbBuis, dzegTuag: AODodaucOtcufqWoof) gqixu goa imr ohimeroohq wo qhe ikapurev:
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.