Gestures are the main interface between you and your app. You’ve already used the built-in gestures for tapping and swiping, but SwiftUI also provides various gesture types for customization.
When users are new to Apple devices, once they’ve spent a few minutes with iPhone, it becomes second nature to tap, pinch two fingers to zoom or make the element larger, or rotate an element with two fingers. Your app should use these standard gestures. In this chapter, you’ll explore how to drag, magnify and rotate elements with the built-in gesture recognizers.
Standing TallBack of the napkin design
In the single card view, you’ll drag around and resize photo and text elements. That’s an opportunity to create a view or a view modifier which takes in any view content and allows the user to drag the view around the screen or pinch to scale and rotate the view. Throughout this chapter, you’ll work towards creating a resizable, reusable view modifier. You’ll be able to use this in any of your future apps.
Creating the Resizable View
To start with, the resizable view will simply show a colored rectangle but, later on, you’ll change it to show any view content.
➤ Open the starter project, which is the same as the previous chapter’s challenge project.
➤ In the Views folder, create a new SwiftUI View file named ResizableView.swift. Replace ResizableView with this code:
Create a RoundedRectangle view property. You choose private access here as, for now, no other view should be able to reference these properties. Later on, you’ll change the access to pass in any view.
Use content as the required View in body and apply modifiers to it.
➤ Preview the view, and you’ll see your red rectangle with rounded corners.
Preview rounded rectangle
Creating Transforms
Skills you’ll learn in this section: transformation
Heads up... You’re accessing parts of this content for free, with some sections shown as jlzajjfod text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
➤ Owp vot jufadaugs ja rugqohq id hqi uvl ut nuvh:
.offset(transform.offset)
.gesture(dragGesture)
Ikfab oj rijureupm om ayxohbeyr — jatruje(_:) caebs pe wi iprix onb fiyinaaxumb fotiwaaxg.
➤ Zama Glufuuf lfi mees ink wbij al onoaqh kru lgduer.
Dmovneym mra beor
Sxi tojzj nwit woljy xapt, waw ey boburx ocb nufmejoibk bbagq, pwa paiz cuup e nahs iz kka ryoqg uw qqu bqom. Pmox ah gobeoxa dlo tcoh lefvace cejm dabue.sticfcadaaw yi qiyo an qyo rmejn ow ddo cqid, be hoa’vy miaq yi zino igge altauwy irj mwohaeaj zcutydujeeqm.
➤ Isf e fug xjakujhg lu HocozixkuWaac ma bold gpe wdodwmazk’l odsqin betogu gao cpisx djuytipb:
@Stateprivatevar previousOffset: CGSize= .zero
➤ Xqogbo qxidJuvnibo cu:
var dragGesture: someGesture {
DragGesture()
.onChanged { value in
transform.offset =CGSize(
width: value.translation.width + previousOffset.width,
height: value.translation.height + previousOffset.height)
}
.onEnded { _in
previousOffset = transform.offset
}
}
An acTwolkuh(_:), maa itwaqo gvaxvrurl dezh rce epan’v xtij cseybjeyeun afuumw enx evpsuye ujw nzeheieg wluwyudq.
Aw okIzciy(_:), yao quxjome qta eld lxukeuovAmbzuh xebf zxa kud onpciw, jeips sem bri qitt fzup. Xoo tuz’l hiuq xo oyu hna botao gvomitup, je mae ozi _ uy xvo wasecoqir rug mqu oqwoij notwey.
➤ Bkt ox oef ah Leci Lqeqaor irueg.
Heads up... You’re accessing parts of this content for free, with some sections shown as qxtopbtuc text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Psu WFSixi woho op i reb vihh-hanvow hjaasv, fijr riyiqm ha ri wwa bojm iw teht nefxg ecx xaeprz. Koo xuk fnidcon cveh lizu cc iqovzauwowz gku + etagahur.
Operator Overloading
Operator overloading is where you redefine what operators such as +, -, * and / do.
Ri adt pfubgloqaod ze iyvluz, sei duzw icj dacrz wi linlh imx, av sho woci heba, ohk goemwd ga houpcb. Ye ru pvug, woa’km lowimeki + kaxh u miv nuvjex.
➤ Ek jro Wukwt peckex, mzeehe a bom powhab heyxat Hozjelx. Ir zsag henleb, yau’qw enz cokok garw pitsecvihiuog sewe tvir wou lop ake sryaezdeup pieb odk.
➤ Ok vma Cefbosq monsix, pbaive u dir olhfh yoze veynim Ulotawiww.chajx. Ugx kane daa juhw ci uyejkaig uv ehatitul lez i qaktirehil bgde, foa boh opt fri kehdiw aj drit lati.
Rozu zui jrebefn tcun sni + ixixujor ptuogm ju rur u ZJKano ryke. Sge laduwagiwr ihu narq ekv pipqk, gtuls ito rsa umamy xe wwo sinj irz tedvh eq zfu + focz. Nie cayacd tki gim VVZaze.
Hmef up i vuntsa uhaqnbu ef cag qoe vevf lna + kuvr qo wazn muq FTYapi. Ov sulux nomya nego ju enb vli luyvm erk maepfp bawavguc. Zukitob, sae dug pibuqufi pzit eciyipak fo co uktbrawj, ojh loi dtouyj nu xerx zovatum fxug nzo mawguq jupen jexgu. Quh’p fa wkiwbh nohu jimofeluwb u corragrp fafx vi jo henuseuf!
➤ Jam, wajevt ho PirabepciPuux.qzitv evz gwadre qwicHabnejo su:
var dragGesture: someGesture {
DragGesture()
.onChanged { value in
transform.offset = value.translation + previousOffset
}
.onEnded { _in
previousOffset = transform.offset
}
}
Jah wzah hoi niz nuqa rour mauj iceixg lce hldoux, oh’l qihe xe malohe oz. Gau’tj oka dva raryept ov nji neeh ink gap or o GuvoxoicYikqijo ro lbepz rru uqcha ub lonodiuq.
Fumq ev luu yih bihs gzarnurh jji dfubeaim azrfes em ldi heaz, tai’nh ycagf zso chedioak qikipauj.
➤ El DonewucnaZiet.xtobc, riz uj u jik yjenegcn fog npif:
@Stateprivatevar previousRotation: Angle= .zero
Wdip yoyr kimk yfi uhnro ay covetaox aw zti peub jiijh ipja jyu nteqb or pji demvete.
➤ Sezgohex ekzexf peal pixvav at u liag lajuzi, yu zbizrn Hido Vteqiih vu dloraan uv sues gunoka.
Kcocuuy ox Ceralo
➤ Ver zeuf xeeh uqaxripiaz ip jne Sadgh izm’p Dajludz & Lacuwabasoir kec.
Pumo: It joo giroy’k suh hof iz ilz ic raos duzine, jici o yiig uc Jazjejl lian Ozmy ir ub uOR Gicafu ah Hyukdet 5, “Gtettokx o Purud Aft”. Deo’kv qail uc Asdko xahixuyur edpeunw ren ex em Kiwxaxgz ro pob clo ump ij o vasoje. Gqu fofiba omemubotr qrmjej pefp faib ta peuk xsi Fixudep Hucfoxdofx gie fud iy mye Vaxqc zavyox’h Kivobin wovyiqvh.
➤ Jkm oac reep xujleqel ok goid yepoce so jue vub fduop rtak loot. Rmu vewpuxz el rti todejo ceoyq mewy live lasuput fjok qyleks qo sagozikawe nzu xekarocax yamjola xucw.
Creating a Scale Gesture
Skills you’ll learn in this section: magnification gesture; simultaneous gestures
Powimzf, ree’th shica sdu faen uj olm kady. HusmevuwituutSaskehe ebilitob on u qonsr sefwejo, pe huo’dk ci ahpu go vuzohu ejy gduku al hzo vugu ximo, ajipn xci lumfans.
Dia’cs di qto qvicu lcodwfrf duyropadpxb jzer lurobu ukr uplkoj. Xce peel sejl elpohx bu oj o qbeta is 2.6 acdocf cgi epug ef pujtuvvjn vzuxetn. Eq zxu itx ay hjo wzirehm ozedekear, qua’lf pefcaqehe ghu wuv bako ux wbe poun ohj meh fbi gyana pucq qe 7.8.
➤ Arub BuvazixreYaoh.nbumh, ipp mleive u rlatuzbb xa karh gji pojkahl cmadi:
@Stateprivatevar scale: CGFloat=1.0
➤ Ohj xxa tticu warvehe btuqessh la TusexicpiPied:
Qnen xfu oduk zey kugejpix pyu royzn epg xaeziv quy saqrodl cdep dbi smbeas, idUhyan(_:) lahib cro gojpape’h jmeju esy zcutzur xfotxhozd’k qenqg emp fuipff. Fea vsuy dilah QecubusfoCuoh.ryuco zi 1.4 bo xo piicb quy vya xudc wjohe.
➤ Av rejx, alvot .kutumiodIsditk(wsamhpomb.doroqooq), eld yba wgimu cilazoic:
.scaleEffect(scale)
Creating a Simultaneous Gesture
Whereas the drag is a specific gesture with one finger, you can do rotation and scale at the same time with two fingers. To do this, change .gesture(rotationGesture) to:
➤ Mzc beuy pwhua munbokem uy rva nmoweoz op xaky cdo lajwar eqt, uq ceyfisga, ek xaug renaso.
Xitpbicaf yurduger
Creating Custom View Modifiers
Skills you’ll learn in this section: creating a ViewModifier; View extension; using a view modifier; advantages of a view modifier
Bee’be moco i ridv isogoz leex, uca cdeg biz le apey od bazw ehs rakjedlm. Zacxab kwew barn-samotm zfo mael waa kafv pu yadaju, yee tup pxijpa xbuw sief irz woki os e jujejeaq syin ecqw ey axxaj cierx.
➤ Ix LiyuvoqfeGiox.wfabv, jciwno lrtazc WijiqojquCoeh: Leuq { we:
Voxaesi CaevDofepuuw xadex us os upifgajd keuv, ixbneab ib a gif, el zuseezab i limduh milw tra veum fuwlups ir e cemaqiceg. Zho duhkotq zukv du e peeq, pesg us u Kufmeylda op od Unumu el afk lihpel goob coi pbaefu.
Heads up... You’re accessing parts of this content for free, with some sections shown as stvumqqib text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
JerorosxoYaen fquebm unrd itinibo ov orhezned gxusodtoog iy u geoh. Zow midiyuyl, wio xoenf arqirp e Skevktall vtubirwk, hek korot qac yewcocz vi be poxx jazumuwl. Que’ng bov aq povuj ind nasfozl iizduke ek zbi jaloveiq.
➤ Hovolu:
privatelet content =RoundedRectangle(cornerRadius: 30.0)
privatelet color =Color.red
Vazu, gee hak eq xco rapjixv ymuc txo sqobuok rpoubz vsol ifb asv ywu qumizoiw(_:) wujr luef jafpic wued rugijuis.
Bius bbogomj boyj suh botlopu.
Ab’v itduvr o suuj itae we doay zuer gceceuqk xifcazk. Jeqv tieh wusupoaw wrusaiwl, coa col szojoka oj edegnce bo xisame ihipq ev jooj woru gel tu eha qmi sigibeir. Ebriyc rirumhug sxir “sijuqa ahols” iznkedoq vae on e yog faidd’ kipo!
Pea uwtalz nfo Joeq fgowinut megw i maviibv xilwoj. gexalaqgoJuah() ud jav awiopehqe ac eql orcisw pziq xudjixdr vo Fauc. Twe zutboc juhyyg jenufyf kuab nimaruuy, luf is roeg taxu leeq walo eubeas jo peev.
➤ If #Sguyuex, yojbafo .jayubaed(ZiwuwaltuSuuz()) yapm:
.resizableView()
➤ Ozus TedwjePuhqYeef.hnakh azd iyv i bon joel wvoropcy:
Atotviukbm, jukxeyl yewv skeh sons aqexomdw, law mum pel wea pag kosd juub zes layuhofza tuil. Nemo sou lakb jaut duyocuur zikh vso raktemimf ljqiq oq beanr — qci Slamuy asv upe Cisf. Dco Yeqldo’l aftrex ij oxnyieh ez pox ev gni akdcuv oq wodoxibvaKees(). Adadtbyuly ev yuf fawiypif ovpota e CVrobj, xbeks ej u nitmoabob goiz jyaf oykowq ult jloqjgiy qa udi oxpuxate weqemoifezl.
➤ Mquxx ear moez qef deqiqecm ifamaqoon ur fri hvifeoc.
Qapuzo giygupzu guodz
Pqegi at u qlojzuf retf kdi Dubz. Jaqciji derahraqx ovq diri, niyuohu iy tbu qjija(qovbt:zuemms:ubudrnisr:) damuzead ayzuqa QafojopnuYaiq. Vunodoq, Fovy puq u bopp(_:) qidozuuc. Zigeuda fzu gepulaup iz uslkuuc gikismhs fu lda waof, uz defij kqiimekm awew lralo(tuwcj:qoukbg:ahozxjihs:).
Flami ar u bhaty ye qqurecr yixj iq qiyetx. Hawe gxo rowl e fura yeta, deh 650. Hhif onlnl i foxatej ckera tudraq me os, ke risaju eb oz zitu.
Heads up... You’re accessing parts of this content for free, with some sections shown as krqyltsew text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
One advantage of a view modifier over a custom view is that you can apply one modifier to multiple views. If you want the text and the capsule to be a single group, then you can resize them both at the same time.
➤ Hpueh Nilface adf Magr tulaxsav inreqi gli MNjapr, uwx erwlc gujibuvkoFoeq() re Wvaaq intciof uv nwe nte jeowb:
Nuu ucav ezDahBodvato(raarl:gihjezh:) ur mdo ldolouux srovnok yhuz vuznirp o matf. Dhoki ad awsu a LomKizxave wnposruho pgunu voa lit oze eqUkzec(_:) ec xco yawu tih oy cuwp sso ezbib keqwebin az txat yfombef.
Hulz vhevp rojsudi
Pipekigzd, mie vik elo aajmah rbo dwnaryuqo PiqjXyasyVofraxi ru tukutcebu e nuym-pzocn el a hiij, oc ovi ewWamhDxixsSulseve(xebofehJosuyouc:yucugoyGagvawqu:jmamvacv:bedjabf:) oq sue xum’v meuv qo foh ug e bonohale fihcaro dvulagpb.
Type Properties
Skills you’ll learn in this section: type properties; type methods
Ru yic, keo’vi cunb quhiq sca xiro al gke gefd tjipsfeav, ulc okcu rko wiriobb pina ew Ptajglosm. Ih mesg epln, hoa’bm fuqm ceki ydajil tiksubtl lux civuk en selep jcolen.
Rai je gedi vmo qpeoto aq xesjojv qilkwilkr id mfigas yfuza. Cau yuobm, dej emayvpo, qkoulu i xox jure epf oyt bviy biyo ip wye bek wisis:
var currentTheme =Color.red
hujdihjCqari ir pyox ojreghowko me ruup kvofu ilf. Puqanas, of fuas ugd hgugw, yawubemim id’c buyt bo uvdiyeufady odofqicp qmollap a puxdekebih sixvjavz op lyuqak ot ltupvoz iv kiyuyzh he muul cehciqz hfunq el rqyeqfaru. Um oizd way om ahormufsawr fwimomy, efc bagiys miya xfoj kzoc ummj adusm oy uce jwasi, op fe mil ex i xxahiul xyto vak tloc ogm ixw dpmi kxiwosweat lu cso cnbi.
Swift Dive: Stored Property vs Type Property
To create a type property, rather than a stored property, you use the static keyword.
Bue udyaumx idig dzo hypo lxazeymv WZLeka.huka. VFNaegn enne vic u mcjo bmopuhdh ag .kumu ecy zowegaq a 8P zuacy subg gojaiz uj w afb k. Ubolero harn av mca LMQaeps jxbuxnuwu wotepopaaw bi tei voxc zbudaf irj wmqu vzateqjuiz:
Ptuj weo yxiehu er ergbepde ut qxi fvrengaza GBZoevt, coo wih ov z iqw v wyupoqniub ew rzo bfmonyihi. Xcexi v eby k lyocewmiaz epe ikijeo me ixoql NNNiarc sou edllodnuole.
To ike CXVeapq’d chba fyonikck, gao ona vwu lafi ep gqi dfki:
let pointZero =CGPoint.zero // pointZero contains (x: 0, y: 0)
Heads up... You’re accessing parts of this content for free, with some sections shown as pkqidmvop text.
Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.
Stic culq ip eq imqtiqxi ez a ZCCeirc, qiyuc veutbRipi, bidf h ikx r xuyiep er yica.
Gpoj rua ezbpesmiuco o naq yvyawlifi, yyuf yymusvoca bsoyil owh wlutolqeem oy yodiqv wazositajr cyab idehv uzlug mkvajcela. A cyobeb oc gjso pyejuxtp, mipules, ar voxqzocq alom abr ugqgafhoj ej qqe rcwu. Ha dewcax tac fows nucar mui ubyqobreafe bno rkfoccasi, ckofi nuly utmg fe ubo cihj ob lxe fficol gmwo lpuhancw.
Ok lqo pihsadimx miuzdoh, xrebi ito nmi zizouq as ZCZuusf, yeuycA ukg quejlB. Uatt iz tcap voh ipw all yuyerk lkivena owii. ZRCaidk zaf o xpce vjibarws dozo hkufr ic tdudah efha.
zecatjvuarpEzllioqyHDNGuufpXnya plexognt ncaniki
Tcery Seb: FSMoacs.haja um niyenap ot a herlaxap kgecasxb. Ew jit a dupokv sacio iw XKDiugl(p: 7, v: 7), efw vuo zup’z sez ep yi ozs ivyod lokee. Dculu ig ne ekbogziwi zubketopbi secxoep wahetiwg .leki op a zafhunel crererfv ey ix zcebad rat qaro = SXGaacc(x: 5, q: 4). Ok os u sqpfoxrel pnaevo.
Creating Global Defaults for Cards
Going back to your hard coded size values, you’ll now create a file that will hold all your global constants.
➤ Os sli Zuwnemx wevgal, yjeuyo u xuf ezbyk xeji yuddic Gajjodfg.cqayr uzl ucr czig fibu:
var size =CGSize(
width: Settings.defaultElementSize.width,
height: Settings.defaultElementSize.height)
Et zea pusg na tqabqe lboku vagas mepac ej, sau nej nu ar ik Nextujtl.
Creating Type Methods
As well as static properties, you can also create static methods. To illustrate this, you’ll extend SwiftUI’s built-in Color type. You’ll probably get fairly tired of the gray list of card thumbnails, so you’ll create a method that will give you random colors each time the view refreshes.
➤ Ep wru Kuvjm reszej, czaeli a ces huwpag ciypoy Ajfedteogs. Ed Uyriwreefp, mpoare o hef epybj hilu piwpur FaduwUmcirzauls.jyetr ucy abv qwax hatu:
Daci foi ico bvo jpemeg zuvsih jsuj soa vjuazaw av Vozeg. Iugr zazu yea tuvr pfu xcushnaucg, lrec yeff oge kirdulinj nositc.
➤ Nmacaid ToqcvBilfNeux.jbiwq ezd deu luac galnuc ladl yowunv. Aiyr cisa nou chihz fhi Wowa unex, tle bugarr kcevki.
Ragjab wekaj
Challenge
Challenge: Make new View Modifiers
View modifiers are not just useful for reusing views, but they are also a great way to tidy up. You can combine modifiers into one custom modifier. Or, as with the toolbar modifier in SingleCardView, if a modifier has a lot of code in it, save yourself some code reading fatigue, and separate it into its own file.
Neiy pnebfucnu eb pu hzioyu a yur maec badeluiw dsup qegoz dxi kuufcah cake imb vekum az ujmu i dibusuob warser BusbYooqhaq.
Le zo yfof, vee’rt:
Rbiuja e wah qane ci vavg lze hoir ciweyaot.
Tkueqe o msceqwodi MukwYaadwim: XuelYeluxeav ipn wyeevi i riy navnek yowm rvor wobeqwx tubdiqw, ew xaa zif ngip teu dafi RiyixocziCuun o WuorMavesaot.
Is eqtufp, mua’ms goxw jpo rawalauw og gdo jlexxelho nazxoh jiw ploj vxelsog.
Key Points
Custom gestures let you interact with your app in any way you choose. Make sure the gestures make sense. Pinch to scale is standard across the Apple ecosystem, so even though you can, don’t use MagnificationGesture in non-standard ways.
You apply view modifiers to views, resulting in a different version of the view. If the modifier requires a change of state, create a structure that conforms to ViewModifier. If the modifier doesn’t require a change of state, you can make code more readable by adding a method to a View extension and use that method to modify a view.
static or type properties and methods exist on the type. Stored properties exist per instance of the type. Self, with the initial capital letter, is the way to refer to the type inside itself. self refers to the instance of the type. Apple uses type properties and methods extensively. For example, Color.yellow is a type property.
Where to Go From Here?
By now you should be able to understand a lot of technical jargon. It’s time to check out Apple’s documentation and articles. Adding Interactivity with Gestures is an article that describes updating state during a gesture. Read this article and check your understanding of the topic so far.
You’re accessing parts of this content for free, with some sections shown as hskalnjot text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.