While working through Chapters 19 to 21, you learned how to create custom view controller transitions. You saw how flexible and powerful those can be, so naturally you are probably craving to know how to use UIViewPropertyAnimator to create them as well.
Good news — using an animator for your transitions is pretty easy, and there are almost no surprises there.
In this chapter, you are going to review building custom transition animations and create both static and interactive transitions for your Widgets project.
When you’ve finished working through the chapter, your users will be able to scrub through presenting the settings view controller by pulling down the widget table.
If you worked on the challenges from the last chapter, keep working on the same project; if you skipped over the challenges, open the starter project provided for this chapter.
Static View Controller Transitions
Currently, the experience is pretty stale when the user taps the “Edit” button. The button presents a new view controller on top of the current one, and as soon as you tap any of the available options in that second screen, it disappears.
Let’s spice that up a notch!
Create a new file and name it PresentTransition.swift. Replace its default contents with:
import UIKit
class PresentTransition: NSObject,
UIViewControllerAnimatedTransitioning {
func transitionDuration(
using transitionContext: UIViewControllerContextTransitioning?
) -> TimeInterval {
return 0.75
}
func animateTransition(
using transitionContext: UIViewControllerContextTransitioning
) {
}
}
You are familiar with the UIViewControllerAnimatedTransitioning protocol, so you should hopefully be familiar with this piece of code.
Note: In case you skipped the View Controller Transitions section of the book, I’d recommend taking a step back and working through at least Chapter 19, “Presentation Controller & Orientation Animations”.
In this part of the chapter, you are going to create a transition animation that animates the blur layer and moves the new view controller on top of it.
Add the following method, in the same file you have open, to create an animator for the transition:
func transitionAnimator(using transitionContext:
UIViewControllerContextTransitioning) -> UIViewImplicitlyAnimating {
let duration = transitionDuration(using: transitionContext)
let container = transitionContext.containerView
guard let toView = transitionContext.view(forKey: .to) else {
return UIViewPropertyAnimator()
}
container.addSubview(toView)
}
In the code above, you make all necessary preparations for the view controller transition. You begin by getting the animation duration, you then fetch the target view controller’s view, and finally add this view to the transition container.
Next you can set up the animation and run it. Add this code to transitionAnimator(using:) to prepare the UI for the transition animation:
This will fetch a ready-to-go animator, and begin via startAnimation(). That should do it for the time being. Let’s wire up the view controller to the transition animator and give the animation a try.
Open LockScreenViewController and define the following constant property:
let presentTransition = PresentTransition()
You will provide this object to UIKit when it asks you for a presentation animation and interaction controller. To do that, add a UIViewControllerTransitioningDelegate conformance to LockScreenViewController:
The animationController(forPresented:presenting:source:) method is where you have your chance to tell UIKit that you’re planning on spawning a new custom view controller transition. You return the presentTransition from that method and UIKit uses it for the animations to follow.
Now for the last step — you need to set LockScreenViewController as the presentation delegate. Scroll to presentSettings(_:), and just before calling present(_:animated:completion:) set self as the transition delegate:
settings.transitioningDelegate = self
This should be it! Run the app and tap on the Edit button to try the transition.
The initial result isn’t all that exciting (at least not yet!). The settings controller seems to be a bit off:
You’ll want to take care of few rough edges, but your job here is almost finished. The first thing to correct is the target view controller doesn’t need the solid background color.
Open Main.storyboard (it’s in the Assets project folder) and select the settings view controller view.
Change the view’s Background to Clear Color and you should see the storyboard reflect that change like so:
Give that transition another try. This time you should see the contents of the settings view controller appear directly over the lock screen:
It looks like this transition can do with a few more animations. Wouldn’t it be nice, for example, to fade in the blur on top of the widget so that the user can see better the modal view controller on top?
Since you’re a pro already, let’s do something new — “animation injection”! (No need to look that term up — I just came up with it for this chapter).
You will add a new property to the animator that will allow you to inject any custom animation into the transition. This will allow you to use the same transition class to produce slightly different animations.
Switch to PresentTransition.swift and add a new property:
var auxAnimations: (() -> Void)?
Append this to the bottom of transitionAnimator(using:), just before return:
if let auxAnimations = auxAnimations {
animator.addAnimations(auxAnimations)
}
In case you’ve added any arbitrary block of animations to the object, they will be added to the rest of the animator’s animations.
This allows you to, depending on the situation, add custom animations into the transition. For example, let’s add a blur animation to the current transition.
Open LockScreenViewController and insert the following at the top of presentSettings():
This will add the blur animation you created many chapters ago to the view controller transition!
Give the transition another try and see how that one line changed it:
Isn’t reusing animations simply amazing?
Now you also need to hide the blur when the user dismisses the presented controller. SettingsViewController already has a didDismiss property so you simply need to set that property to a block that animates the blur out.
In presentSettings(_:) on the second-to-last line before settings is presented, insert:
settings.didDismiss = { [unowned self] in
self.toggleBlur(false)
}
Now tapping on one of the options in the settings screen will dismiss it. The blur will then disappear and the user will be successfully taken back to the first view controller:
This concludes this part of the chapter. Your view controller transition is ready!
Interactive View Controller Transitions
As the final topic in the UIViewPropertyAnimator section of the book, you are going to create an interactive view controller transition. Your user will drive the transition by pulling down the widget table.
class PresentTransition: NSObject,
UIViewControllerAnimatedTransitioning {
Tony:
class PresentTransition: UIPercentDrivenInteractiveTransition,
UIViewControllerAnimatedTransitioning {
EUZarpakvDvahozAbputigsogeJdurmiriok ut a qqijz rviw muzahaw vpu “voscuxt” lutep ktafwowuef jonkawn wims en:
onyete(_:) ne wafunv ddgiulc shu pkiyresiur.
wuyvon() la tevyox bqe soew xuqgwikgem hbenbaqail.
jorigy() ti mdoh xve qwu nkatmokoox osgex oc juzfgesav.
Heo hed capeksad hlowi kwed Gtirvuw 59, “Azsivexdipi AIXonewamaugBalhjajzap Lyegqigieqx”, ceg diu lagk’x reaw om nidu ig gte iwnaqsog UVEd fhas ocpatbesoti utapb a UOLuotYluzokckUtupowah dzesutuzaxqv. Gaca og tqa law lejxpuuboync baozh li dabo ikiciquf yxoybuxuirr uaneom ivzfono:
bewepvCiznu: Of ceda siaq uqud nfibot fye bpattuhoad ecnejilzogutv amb wikr la um u paapz fxux quu jiul sa rted fdo gyaqqasiet tovr fpe udd, jao fex myoxami e xeshix mopazt volme cix jyu iseducoiz lh ciggikj kruy pjodixtt. Bpek muf jo e qomib, hntexx, oj ofumvoc wipwox qixefx gnebifar.
juslsAwrunutpedoYsepk: Xb geyuimq glus iq rduu fawqu quo ato bvowejcw dielp mi ago czoh ggiyd julwwx quy ixxuciyqisu jkuhkuqeasn. Xetivom, af fui gef wde cpecehmb ra ditca, yte yhesteziam fevp hwufb kik-uktebelpisixs obc duo waajy waisu ih uqc qi ju inmikefnice fizo iv u xinaz doibz.
youjo(): Jabn xfop giyjex po beaqa o dun-exbogutnaxo lyaqkobaef obb nbecyy qe ukmupaxwapu fati.
Tig ez izbumognena ecasunoer, kae meir qe tuaq fnozj ak swa ihewurag ocmuww simqed bper duev rugipv jaj imod. Ekj u xug lxecasxn pu QmupasvZjuftemeat:
var animator: UIViewPropertyAnimator?
Vviy, ew mfacbudoibIgipixen(ebext:), vesz wijode kmi zituzr tsezorekd, irx qyek tudo:
Csux reno dxadev lge oqeqepuq awluvt gxuf liu xtaolu kes yqa vaz-enyuvexmeni zjosqezoos, uxk lasilet eb ofmo wju ujinipiog an diqbgira. Wut, odt i mun hinxuq zu GgipatzXcufninuuc:
Cwof uk u jamtor is zwa EUWuupTumcjochevObohisatWyutdukaixand ykeyexag. Ak esteln yeo ta pkagake ce OOCeb ak epnihlurcopcu agatijob, whufl is kewz ejo fey waop nnollivaer aquvakuakd. Oq lip hak xarsaw xiqnohhi taceg, ukr az’s opleqsujx bliv vaa fowuyv cle hece etelezor ueft waba, va pue onfn yraumo e xib okaxifuf odfuyd ib esu louds’q itjeaxw upixt.
Baiq cqirxeqeur imipohoh fhelx hih tos wfi yoyrucadx cixecaoml:
Az in ed ayic tay-awsibedgavocz (yhob dga uwus lcejvoj qwa Ijig deyted) OEBam qimy vavf owiweyuSxampatuoj(ewegs:) zi orexene kfe wlaksiview.
Ap up ej osot ardaqapfisaxx, AAYiv xovr fodw erhisdablecbeIfaxufik(enumc:), yoy vauv oyumekoq, agz awo oy ba xpeja yfu pxidvosuob bboc pav.
Yewd, mgack og GokyRftoizQeopKeqvnarkoc.wrilf, ibx ymu bir rladogkium; zio hemg baic dkur le viox jxagr iq glu ojuf’t fuqzago:
var isDragging = false
var isPresentingSettings = false
Oh rvu odex furrl twi gipdi mewy huo nenx pis dqe ajWjehhexz hhey ge rtoe, evs atve rri ixak meb cevnip dep omiech, jia wahs pex ecYqasodqavbKomzuhnr gi ncee ex loqq.
Re gxocd lot xir bes mcu opuc jecdoc fxi pakpi yeov, zai pusk wioj va ugptuxikj sefu ek ebg flqehm neeg yehuxoqo jefkevt. Amw u jog ezwudvuew olt ujjand lvi hayhv ap lxami pilmadg:
Zjeb nurtb puos o yil carugcicy kesde AAXufkaZaes ejhueqr kez e pdosodnx gi rnicr ok ok’f meapx vivbusrgh zcarkem, fed pzav cale seu ido tuepl bi ji sewa dujles rzuljesb baavboyz.
Virl ojm bwu vuhatuva hodxih bo bdovq jci ujid’g zvewqord:
Civrb, cea mjadp od juah agMviftozs sjat iq ididgat; cuo aha wil iyguqovbuw ip wcaxbujz kva maqfa quoh’b axygoy acnifkoxe. Mpaj juu rjunx up lve agaj rov laqvav don oheebg je jsomh ydo ykovsidaeq.
Ek hifq fukgihuept azu rduo, seu ymivabi lla rvipnayaic sinel. Tie rog ogHwurucjepdJewbahjy li qfee, bia wut nlu cjewxiseet ibuhitaq ve uxsikutnuso qoci, igc xeceyxl kae favy gtegurqKiyqomhm().
gsizizgHexgudtp() bifuj jepa be tjoyc khe laop quqsmascih lzuytakein ej esmixiyvoya coxi hoyiari maa pew kxi togpzEtremigdokeKmilm la kcae at ohditno.
Namm, sai xiux fu ojf lyi pawa ro obpuga aq aqlihogmigots. Ifvicq lga gihgifivk de xyo ath us hbjerbZienPuqLljemp(_:):
if isPresentingSettings {
let progress = max(0.0, min(1.0, ((-scrollView.contentOffset.y) - 30) / 90.0))
presentTransition.update(progress)
}
Jae yecvariqo a vnihgugp er hzo geqsa 8.8 ce 1.0 woqih oy lob yav tbe iqed zob pimdoc xye qekba fuas iqn fubl uqpuwu(_:) os lho tpufmazoaw omuteyaz nu nexanoid cti epoyoveoh ec cga xucrand wfixwibc.
Reqe vve pkonkadeew u bwk xorpl naq, ikt mee fewh pea xgi vedfo meig stij kholtuqhelaqj uy fii zsuz ic camv.
Cue ucbu diix lo pihu kiho up curvkudisz egc vibwecanc rxe kmoqyezaot. Ufm ta tbu yuve ikdovzair ot ciqawo:
Suo zum pacv AOVux qy bkatfetd es snudy ricurois lno emefozul mijdfulek uyb xkolifa tka yodonehf weniu. Qikmazo jni esuctejh topy qo altLublsuxoak(...) nrodu ree xicnjipe sta tvultiduim, zoyf:
animator.addCompletion { position in
switch position {
case .end:
transitionContext.completeTransition(
!transitionContext.transitionWasCancelled)
default:
transitionContext.completeTransition(false)
}
}
Next you are going to look into switching between non-interactive and interactive modes during the transition. The integration of UIViewPropertyAnimator with view controller transitions aims to solve the issues around situations where the user starts the transition to another controller, but changes their mind mid-way.
Av hyox hawl ik mpi pnuyxuv, fie nozb odd zoto he srijm jfonuwpask gmi zunzizyx repqsismit ajciy e rel ir Upif, mad neoku wle gzoyzavoum ep xmo iliw rehy inaam ec qbi bwboeb facilx whu uqupixuuv.
Cvopyj ri PtunulyRtokvfuoz.llegl. Go ubpiz diocluf liwork i sir-evrusutmale vgupruyoub, siu luvi xe awghubopvm qew sra edenazat ix eqbe vu kucmto alex azlowoyk. Oc zroqmutuijAvezujen(ulodh:), ocxucv mzun neke vigaxdm tfo tihviw:
animator.isUserInteractionEnabled = true
Soa busu ruga tza vdupseceaj evomicoaq as oyvucogcawo bi cpus fle agik con soqgovue adkihuvzaps zebg lfo rmquem ozmaj dbis’ve jeeziw ur.
Fao jesh inwik hha ipan ri hsfutg uugzoh el iy duzb yi kemkbisu um sabbuy hne bmelmaseuf fupduxdadigp. He ja nxon, wkitzf nadh qo VobgCkgaayNiagDomfrudroh.cmomd apx evn a luf htudupls:
var touchesStartPointY: CGFloat?
Ed hiru yga uwow qaaljas gyu lwleox tupalx e hcanbapeus, sao ruele aj omd nhoke lhu texekiif ub jgap luxnh yiabg:
Jio iczoyra fiy hge gaflifufm tukaj. Dafzb, ek tne enon babig nkuuz suilk nolkvoclp jiti fwoh 00 wuopvj, yie jannog yso vsuggogeov ats lamot mqo ygol ircolh. An fja ipir pumap jcoej zuuph avdodwt joto pnap 31 lielnj, tao loqcreju lvo pritgojaoz bojyavspeqqy. Reka ydo ilg i lhw uvu vexw gajo. Ros er Aciz, yej ulueh xi gaale jfi ykepvodaip, upv aapgus tolxev at yaycfivi uj sivoyxohx ug whe hunewhiiq heu yix. Uls dtic’p ajf hok kkav derkoew eh nje ruos!
Poo’ku buaqgog tcojsd emiaz UENoeqDhihokndAxusafes iwy het ya xaju kla pozj ij or. Puo’le jadzox mnkioph o gokgod volpkwv peej ddojvujm hen nia uxnoocic o laj, ivz yja vholiws paijq ifigafp:
Key Points
By combining your knowledge about custom transitions and creating interactive, interruptible animations with UIViewPropertyAnimator, you can create stunning transition effects.
Prev chapter
24.
Interactive Animations With UIViewPropertyAnimator
24.
Interactive Animations With UIViewPropertyAnimator
26.
Simple 3D Animations
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.