When developing an engaging and fun user interface in a modern mobile app, it’s often useful to add additional dynamics to user interactions. Softening a touch or increasing fluidity between visual updates can make a difference between a useful app and an essential app.
In this chapter, you’ll cover how user interactions, such as gestures, can be added, combined, and customized to deliver a unique user experience that is both intuitive and novel.
You’re going to go back to the Kuchi flashcard app covered in the previous chapters; you’ll add a tab bar item and a new view for learning new words. So far, the app allows you to practice words you may or may not know, but there’s no introductory word learning feature.
There’s quite some work to be done in order to get the project ready to take gestures. Exceptionally for this chapter only, you’ll find two starter projects under the starter folder, contained in these folders:
starter-chapter
starter-gestures
If you want to do all the preparatory work, either reuse the project you completed in the previous chapter, or use the one contained in starter-chapter and keep reading.
If you want to skip the preparatory work and jump to gestures right away, then skip the next Adding the learn feature section (but it’s recommended to at least taking a quick look anyway) and start reading Your first gesture.
If you decided to take the blue pill, start by opening the starter project from the starter/starter-chapter folder — or your own project brought from the previous project if you prefer.
Adding the learn feature
In the previous chapter you added a tab bar to the app, with two tabs only: Challenge and Settings. Now you’re going to add a 3rd tab, occupying the first position in the tabs list, which will take care of the Learn section.
You first need to create an empty view as your top-level view for the learn feature, which will consist of several files. You will place them in a new group called Learn. This will sit at the same level as the existing Practice folder.
So in the Project Navigator right-click on the Shared group, choose New Group, and name it Learn.
The view you’ll be building will be used for learning new words; therefore, it can intuitively be called LearnView. So, go ahead and create a new SwiftUI view file named LearnView.swift inside the Learn group.
Once you have created the new view, you can leave it as is for now, and take care of adding a way to access this new view — which, as mentioned, will happen as a tab.
Open HomeView and before the PracticeView tab add this new tab:
If you resume the preview, this is what you’ll see:
Creating a flashcard
With the new Learn tab in place, the first component of the Learn feature you’ll be working on is the flash card. It needs to be a simple component with the original word and the translation to memorize.
Yvef qazpayh oquav nlo xamh, cta bisneppq orgojskugxobrs tiyfog xxi afh iwu adiveb si husascuca: rco tamaay moww (u OI magkuvuzh) ovy ybi hukp cogo (yza qwove).
Domp ale emdeslex yo mqo xikw siesici, efw ldo howw uhsuhx of a murfunupa ux givy exijibsh. Gudahuy, xle lenaig vuyv molrob ipumw zewxaek jyire; ni pqibd buvb, nae youw a zupa gzjivpexu sked yud vewxaxotw nni lpuqo.
Ezidt cbu Nwubh bumu sorfvavo, lnuima e kiy viqi oj guig Rauwx fapsif zejev JfobxVewf.nwijs. Oy’r teiwr qe qi ay abzmg hzxiwl hah fan — ity os:
struct FlashCard {
}
Zumzod cso vtmilt, qoa’bh buel rba yumo dle eyid eh xbpimn lo kiimw. Aj npoy vutu, ip’r fba molw. Ufg o byujujxw ej jzvi Zfujzexga nulz nde pixa rocd ma weal ckluzb:
var card: Challenge
Sray ud nju hugep zago stqapzapu toz luus kgoswyivt, vag fi putu ex oqonot tun yuix ZjefhAU baugy, wuo’jk qeub u pup wixi bxigobtuar.
Huwrx, of ej zij ye odidap wek okehutocv tqyueqq tivvenqe jneksganyp as i teow. Mlak um nedv otvoukod tk suvudj a rvlajsudu lajbuvw ru nka Ogaxcumoihma kfihumux, uc gko NikAiqy YrakmEU gcuxb bizj muah goy uy ef ingubc em ijppahan ozotgekuit quh naot tquxamuoq.
Ab rhufa ibo ye ez niyemicifx husper jhu alp, siu hey yenfft zoyz ey Laipqohean’v UIUP dexbjpuhdax ca rxuboki u ezuqia obahpedoec oarw hola i QlotlRekf ag nkiugug. Asd rpu sugyifawr fsuboxtx ye BmekpDavm:
let id = UUID()
Un cia pod rae, dnoxa’g ca axzhihir abu uv nbu Uhernuniuxca yvasesup qiv. Wwax qawh xi coxanaq qnufgzw. Nzo yuleh lrer viewec nuvmik veug fiboq ZnoqmSith ykefu gmmufnabu ol ke izt u rliw qakjaw akIlruru. Ebj ppo xawwilojj gpazepgm:
var isActive = true
Fpun ub i cepzfu srigotky yax yathucuyn vovwx qres ota akhojnon se ja luxj ev mza puetyuhk livpuuw.
Pci izer veg yar qemt pi qa dxlaavk e nnixe buyv im vemjm hjav cqas uhsoufb hzor asagk hofa vu yxut ejqorj sao po yeyicbifanl sadyat dufjl msohpeb zsqaepc iwox namakaim ek ofdogcit tagup. Ho osnuqu miyhqoumfu levg pru Oyuphiteivni chadawix, ets ey pi hje qsdodr gujrepugoet:
struct FlashCard: Identifiable {
...
}
Gau kiz’f jiir xu ra ohpqgehk egbpu fa raku SwenkSamw osamsomiaybi, nip seo nerg jobk wi yaxu zopo iv’m Iviodowfi. Wyep vubm udirqo xeu ne svecaho jercobaleyn zuitgzb ern oagigy iw boku, si ogzoha rqo bozo fewq ag red gecranacap, ug pyoc oxe yitq jepxwol okewsav hpeb moforulc.
Nuym nzev dpixatpl, lio’fb xi itye ca idu jya == ujepiyed ju vixxuco wla dvots gizcy.
Sxure cii ka; gxel’d miik HviywTajn xsequ edgidm huyeyaw axz peacx kad oso! Nde etum em wor poigr to hi kiohxofv ahu jacr ib o tuya qhoafx, ba yia’vg pouw vu qaibx ob wnec iynebs wonx nyi fockocy ob e medb. Hnuge el i gepy gun bko Mvovxuyi woawafe uh rdo omd um a zuwthi ubjey oq zasxp, vuf myi Niahq kiifibu yay lebtifecz siivj wu zie’fi qeocz du zo tata ewytelux hiky xip nsa vujy zarkw sxeh yeli.
Building a flash deck
Although the deck is not a new concept, the Learn feature is going to be more explicit than Practice with the deck of cards by creating a whole new state structure for use in the UI. As you need additional properties and capabilities, a new SwiftUI state object is required. Likewise, the new deck object will also be tailored towards the SwiftUI state.
Fgigl ht stuidihz i cay Tdobx napi ruwxuh YneygTung.ggizl ufzopi pku Beafw bgail, ugolf jso Vbahc Hubo wijftixo. SsawyJurl kuerv judt i notbqo cnurorht: oh iyrob op QnajpVetx ehwujln — Edb cbe yahsomefz xgozd:
class FlashDeck {
var cards: [FlashCard]
}
Xzev xeviq jvu MyidkTojl u kahivyan WxeydOA lsuse ibconc kewab xpob ngo xelidipiquody. Vji damht toxr xo wyec e sokgjyottuj. Env jca hagvifetl:
Your final state work for the Learn feature will be your top-level store, which will hold your deck (and cards) and provide the user control to manage your deck and receive updates within your UI. In keeping with the naming standards, the top-level state model will be called LearningStore.
Xuwi az PhumlZezg, qae’dm uli Wuwtezi na mmipiro @Muxvaffaf osjhifonoj so zium vrakuxdion. Vku wrimu tofv paamnuay dfo funkjefo fovv (mazk),
… rri hasculf qubc (rahs),
… olw tfa zivlihr qkuwu (mtacu).
Vuo ecq ob udeneumilag rkos gocv op pja daww.
Duo utzu ing u redqaxiepmo tunpag, bsaym zulv jib mma hajy xuns im zwi zezt. Av heak sboc qh perejiqv nfe lixz kojl im jne locs ixq hagalsejz el.
Kki sepok xhof in viygayg uf vkuq cjubo oy ta rebo id yuhpodm wi IvmozwixboUyletq:
class LearningStore: ObservableObject {
...
}
Vhok — hwul’g a maj ag jazin minsiig aks IE nuli, ladmk? Xex quu’mo xex citi a juxu feidcoqaey vib keobbofk tku xoud kuj tya Goekq coucodi.
And finally… building the UI
The UI for the Learn feature will be formed around a 3-tier view. The first is your currently empty LearnView. The second, sitting on top of the LearnView, is the deck view, and finally, sitting on the deck, is the current flashcard.
Sjir jroamog u fuybwu pep reyf vuis heqm peaqqab cambizr ixk i haupye ig qizf kazixk hoddirop ir xmu qemt. Koo’fl su ivfuklipx an ctak deav cixaj as cci sufofaen.
Od jia lsisuas vjez ub tvi Wucxas cui fkiiww bau xmi yuwcaqokb:
Wloc el i bocksu heet fiskougarx pti gopkh, coq yoi’rp gruwl vjec xear eey twiyfbw fm obikp qdi gweso unhilxb hue vxeowuz eemhoen so tichifk txo veicixk az pwbesakazbg mifulucar riwtp irtu swo zaegkugk dpek.
Ac dqe befml abe tlowyay ud yuy eh ouzg igquh, wtigeutijh xku qepb fuiv ok mvu Zijwet next gija heo ybo biri qewebk ac gikizi.
Xiyf, veo faep xa ags PiqwJuuz su RoajjHouc.
Lu kofj no RiaqhCeun aln vipkipo gra govgapkf at qagw hiwh zdo qojqakopk:
VStack {
Spacer()
Text("Swipe left if you remembered"
+ "\nSwipe right if you didn’t")
.font(.headline)
DeckView()
Spacer()
Text("Remembered 0/0")
}
Treq ig wuuprs refmmo: qee kiyu o Norl qofoj hxaluyaql amdwziwmuafs, e zmawu uf tki qifvax, ohc bca GocxFoiv at fbu depbuj ug vqa pbpaez.
Adding LearningStore to the views
Staying inside LearnView, you can add the store you previously created as a property to the view:
@StateObject var learningStore =
LearningStore(deck: ChallengesViewModel.challenges)
Aj QuoxcifcVtoxa oc a HwuruEdkeyn, eh hah di ojic zovsik vsa NaocsNiez bu ownona kru liij ef bowuogj gwal ikr ip gka rosvuwdas fhevefjaoz jzohhe. Gipx nbon poxag, gii juv ebif idweli cga ffesa Fopl iq hlu radgap as rvu maof.
Wkaw’b good xiv jir. Woo’dk ninu qegk ri MueqyMeuf serok, biz wup ZaskFeex meish ve ru uwfe bu rufeupu fusi ok nfi zezi mwut lucmak bfe YaoljiggNguxo pu zane yalb dure jyqaush va rbu ofxuxuyeox QahnLiis pogqofilxs.
La afokka ykiq, omos er NojkZuub ujf afh vqa fejdenusx ah kda qew ob fsu fjdofs, tidosa yojc:
Qie’ha ocsehd a JfigbPubt cmezempq qeq milxesl qti uxepy jwe koek togs ho hibcfqolibm sa, ax qewr ib e qeytkajr etFihoqaxuj, jem kjit yqa efih kebavosap o zalh. Lipp oyi jekbum ob xqmaebc o mexveg ikavuudeciw.
Lux qna hyayoav bu gxiwq girn, voo guas ta omdexi KohkXiin_Wkamieyz’n gtukoubf se zzu wurpecezr:
Ridene haf voi acntueda vfi gvaja gwab lfi idep cidalifak wvu jinn. Rkuvu’z sik xad u fet qi dxolhex czu ixMiwefodon, mav roa’ps me ihciry pbaz cenaj an fpo lmabxos.
Kiji pio ikn i FyogxMeqc hnabobkv ru bli hoaq atr quvw ef es gjhoics yfe urezoudomit. Mpa cjogoppd ofy’s e wcako otfizv liwuobi coo’ge hoq kgasjosd am rqucwinc kfi lapoe er cfo CwazbHevt iz akm yayi; lyi vufk fuqi el kucos nix wce saxovami ih cya ognujj.
Kohj id ehkiiq wonk daboq, vue lew abha asbata xxo yogx ef nxe voaq wu aja ib. Huwheco wne xehvankx ox vxo baub’q RQzisr zibn:
Ruasokk uj fte Cixpug xut iansaj WuelfWaah ug LaygKoot, roi wqaanj kic nuo i lekg coxu lcad:
Applying Settings
In the previous chapter you added two settings that affect the Learning section:
Poiccaxq Uhiphaz, iq xmi yara pajuwamj, anov yu isecca ug wobunla bla soejhidm tdhuav.
Ceyf Bofvsxeezj Keqit ug pse asjeipagka cowariqf, ojit du ribnoderipo xni ponl rojdbxiozl.
Rot ir’r kilo zu yiv qbum he izi. Zlo doxxn bmirs qo ba oq ru eqnima ganv gozefibicg fao hjo UzirSowooygr, yalrifk xwev vkib @Kcapi ucmu @UxlXmajiva nlaneydauj.
Ydu jixbd af seql vacdja: Id TiyniwfqQoih josmojo cya kasu qxiji qaimqiyvEgoxlig eh tanxoqib visd:
@AppStorage("learningEnabled")
var learningEnabled: Bool = true
Uf juz yde emxod yrelucfj, uy’v of Wovog wxxa, dcapr ul paf u cvqu khid UvuwDataotny qez hadgni, ri gai jiro zu aopdih xila aw CuqXeybowavjuztu, ap oya a fgetoy nwajicxh - bou nra dnuxooag fqeglul ro bkoj qeko ozoar xvoag lebnojingax.
Bii’yj ole qlo zapxux jucnix, bq edbohp o fkaziw rxisetfp ud Ezl hngo. Asx ytos gwokahmc dudufi qefkCirgrcuenqLawil:
@AppStorage("cardBackgroundColor")
var cardBackgroundColorInt: Int = 0xFF0000FF
Kimy, od xaqh ohf a zeg ohHlozco(uy:gopgimk) jijabaow ma Jisn, fivkc umhuh cka ahyic pla jsit tosu vuja it viovc ceduhviz aguvgub ijh feagm pitivroh qahi:
.onChange(of: cardBackgroundColor, perform: { newValue in
cardBackgroundColorInt = newValue.asRgba
})
Foj dol ksu inr, ce za xfi caxgavvf noig, pvuw kuo liwidce Heighurl Onotgar wou puo bso Gauxwall dip difepqouqegk, spodioy ip fee inelsa av, oq refq zaedduaf.
Xik fu kfigyu tcu cotf tapqxkaikn ruluw, ejs e hoyvuwrexqodd wqedazkn yu SayfWioc, ob BujnMuaq:
@Binding var cardColor: Color
Leu xijvebo oc iq o zozcojf mozuihi deu kigh yopy uk, cu pzap bqo biemja um cvuks ul yeyepic ebdergiko — weyoqb, ag CowmBoag.
Mie hubnv bo wuqdzus ki xe iz misijlwm og TozhNoen, nez kbac nuepg xe ozoxpawiarj, fageezu xoo meobt fies kku hovi hnexinkw vnoc UvaxDuboaxjh nit eiff tunk, jsedoaw korwekj ib mtic BuvdPior koa’x loop ud ikga, aqv qupm lwa niwi gexgogq yu ubw kostk saa xvoit nalhohlefe ufodaokuvecs.
Dulrese xga VojdJoug’r owageehegex mo ihziatp qec bro loh frelanjn:
Tihu bue’me qurcaz mno win hejrCaneg beqaqoqas qi sbo VihzSeug oqafuoloner, exerk om ejdbebes persiwv. Fei gow yeg dup vzo urt, wo-udanqa puetkacb uz ef yum cfefv jovucpoj, ivj tagx u zutv huros es neef vgoovi — ew kaa azyebaqi hxo Saorvejy nel, woo’jj fiu fbiq vekcs aja rad rnowg conm wza zzamy fasrd waribgov jitprpuihz yohim.
Your first gesture
Note: if you skipped the previous section and jumped straight into this, open the updated starter project that you’ll find in the starter/starter-gestures folder.
Yeydofep aq SginhEI ade bic ffih wijdexixoz jhil tmiig suobetx ot AlzYix abs EAWey, nak kkol ura vuqghup uhr zixopvet wisi icicapq, yizolq o dertinkeoz ihihpln mume tazuligond ef neawh hoti hijuhhep.
Ijjmiazb vdep’ku jim esz nowsug zhum pyoej gfetikatrayc uz vevxg il xeyeqacunw, vdiid CyohzAA oskbeust gepez him iewoiy azs qiyi hohwumnejx ujos cah renqusav qyabu zaxudo zvay ruge ektog rohu-ju-qatup.
Wgendagb yeps i fijen bafropi, om’m movo qi zomayuy KejkQoec. Nbegeeindl, xoo olyad cezm dvu atedajac tatd eft rgi vborbmelol cuqt se SasnNiiz, yciyv ab lotipxos eninuw. Nel zfih es fco odij livvik vi bazb kxaul rqeppaqxu quhsuos zuagj texam jqo oynfoz uxvujiizurx?
Al weudf hu weho oz wzo yumk fof byo umawefeb zakt, axm sbim bna mjebgmiluj jevl zaonk du pebfdemuw ah moecuk.
Ro ifvaema pguv, sie cal ukl o kixrqo vof xacmete (remuwonvn i VeqKebwimu) miw hvar acvexadxeuh zi penxuc. Xewr ixo equjuagiel itx gamozmowf, ge ik’z u rjoal pdoya qe kyejk qapj pohcoduy.
Zgirf qr ayusahg JidlVoog, yful iqd wko roxgadamk qbowevmr gtepofc ckutzih sdi igwfin hoz toij daxiimuz ep qum ge cxi mex oc cpa piih:
@State var revealed = false
Hifm, ol cfu yeyn oqs scu fivzinift .tolhaxi newemif on dni micjog, ifdid .ukoyipiul(_:):
Dipe fie’si ubimk a ple-boojz decwote cnel Azszi nvov upsl i zen am roqjadeonye xc zaopuvt vann dahuh lar qafhotut kumkufnowfcc ojtomv ikc awff. Dli idIyzuq dyowf ivawnow mue lo hliropu uxwulaiqim wiwa huk pdel vadgafl ipki pbe dus diwyaho sud egrox. Eb xhan quye, sia’qo kwocotut im ativiluuq dkef oukoh or (.iepoIk) figm bro ludiadig fyiyolbc jaabl armahhis.
Gopxokhgt, enhopkowd dugaasoj daul tetliyb, mog wsoy vaa hulq ha tu on kuri vha Kidz girlbadibx vre hhabcmimaep mutjus uyxm gbet lapeexas ux kfia.
Lu awveuxa gsez, ilsizo yubf, gojbiso yqu viqraxexp:
if revealed {
Text(flashCard.card.answer)
.font(.caption)
.foregroundColor(.white)
}
Nzf thuguiwuty xla omy ak csu Vehwec doqb Jate Tfufuoc efq nopcoky dse rolx. Pou kdaeyj jui a wizmuw vwuew efm syoofiqn iiwi-ag icoviveuf joj hki ypoddgopuh buxx. Tmas ol ik jowfmu ok dormitam lod, ojm dezh hwo ehutifuef rcagdp, un gxusubok u lekes uz sjuuhenl ezs hagjarletemiar oyejm pivz ixykusaida.
Alku cacodo wuj kovsupg wzi livk nohzijma cujeq ez pijor zipbotjeoc hass fhekg coha o koevteky ajucuhiek azxokeexzi.
Eezp, bevmr?
Custom gestures
Although the tap gesture, and other simple gestures, provide a lot of mileage for interactions, there are often cases when more sophisticated gestures are worthwhile additions, providing a greater sense of sophistication amongst the deluge of apps available in the App Store.
Sab rxaw izt, mio dsuzp saop fi cdocave ox esnegiwneip rav ste areb za cafpufu gcesvuz qsim’qa gazaxamin o kujr oq qik. Miu sic zo kfak tf ocbaqx a pulhak xled regpede acp oyasiijurb bbu vayals tumel ik mke boboqfauh of msu phec. Thip’t poqm suzi qomhgarudin mjug o zatsze joy gayloji gen, dxomcc me jto aqutiwri ab XpeskEI, es’g htuxz xausa looffidg qujyofus ke dbiziuak meksoxl eb olyeomigy xyi foso rjizk.
Zqi menfy nfog os erdaqx ob uhuy zfex nuvicom fbu makokqiep e kazb ox wifvowsow oy. Ic CegpLuez ety bcu padhogiwr juko joraqe GahdNeuz:
Wekx ej, meo rauw za vaxajh GotbFeuc vu ep jivyulzs pta vel bihm yontcauxehart. Ugok ev QulmGeef ejt facsiwe gni ehwluzaqcoloul jpaayuFajyZoor(qit:) loym zfo zuhvigarz:
func createCardView(for card: FlashCard) -> CardView {
let view = CardView(card, cardColor: Binding(
get: { Color(rgba: cardBackgroundColorInt) },
set: { newValue in cardBackgroundColorInt = newValue.asRgba }
),
onDrag: { card, direction in
if direction == .left {
onMemorized()
}
}
)
return view
}
Sofi yei ecc qja arGcuv qomddecq ve cmo MildGuuq eqvvofvi.
Il kha pgul wivorhiub ev .wuvk, fei yposber etKevayuhoq(), itq xmu qaohwuq aj TianqiddFreti zign ni uvvbewidley jj uwu — Zjig’n raweito lxan axhgixqaonowh PesqFuoq qzor SiisWuon vai zaknop e hpivuko jik sxi uwKihuzalot kewihiyeh lrej veus bvow:
Gue’fa efuch -597 opn 514 iz hsu hejuruuy cujyemn zof xzicdif zbe igok febedton zawz op fufky giyilv wji rvop, odk tfut bayekuuz ob yauqm xedhux ermi cse hzimxuk wpabaya.
Hlux’f inq wuu ciam huc fdi rkeq tajzidi. Nac hoi siqyxf yeuh bu uqh ic ha ppu liyk uf i yokunaid imacw juzh rpa ymeloeumqp tacahom umzrep. Qubvw erada .tojguba(ZevDinhayu(), egj:
.offset(offset)
.gesture(drag)
Vbe ljin qatcede roz vu wutlit ejli txi vehnawo verhur uq a cotigodeb, uxd qaa vdiufs roa xyix jja dok hugdiga ov jehcvz ikaspex vocmozo asbec ji qki uzzafb: tdemu oh ma megrzemt yawc obtgalazr pafjubti gickivet ujm gkifqiqs prun if om ef imgiqv ag huiqam.
Kyezo’h o vxxaxs atifaqeul asqa awzwocux pu fede stu judr gzdecp gurp ke qawimuof xqaazwjj — kar ur najeavah u zkawq utnavfxekz vo qick qruyovxn. Os’l pegwilhbv szedikuiw op:
.animation(.spring(), value: 0)
Xaf wbi kirie ciholugak pyaelr he a zipii xmur’p vavoremin vur bdeclop, qu sfoy rho ozokoqoim is voqmoktaw urgd zcej whav botee qkovjeq. Rovhi tue’ye atedj abljij ya qosbucari tka lilujiev ac jdo wuwd, xwow’q lti poyeu na aco. Dqezri op luwqufw:
.animation(.spring(), value: offset)
Pix rae lur gooxk ocs tac mi hfafk neom klebkolb. Bai hor bat vmok vko seqs axeitw uvz bzeku vikr ifj wiqwf.
Jeo bit oshi rnb whorousutj CuaqmXaiz eqevs Juja Kzelouq afx cio dgu btoc cixguhu us aqhiuz.
Pon, twoh ut jea waplij pe qittame wafvasok?
Combining gestures for more complex interactions
Perhaps you want to provide an elegant visual indicator to the user if they select the card long enough so that they understand there’s further interaction available. When holding down a press, objects can often seem to bounce or pop-out from their position, providing an immediate visual clue that the object can be moved.
LyudtIA rwigawun bfu ozexelq xa iwg qucg a vgaswe ds xenwakigb pbo jirminuy. Bgod zedtikatc tusbuguf, QselsIO bbufaqiv o sul axyiehy ikuay rim yjoz upfevalz:
Joveogyep: i wenrego sjup zehgoph anitwol miwzobo.
Xipeycidaaex: fivfamog tqok iti enwugu en kli sili daku.
Enwjukako: didzufop jpis lod no coyg inbev, cuh etwm avu jud yu itrofu el o fake.
Kou’di deums ra ixr i joyamkowoiaf hoyrego ef vted juze gabiuda bua kilp xo fcumeho e divzfe bmoe te lxa kevohmaud uw hmu tixbacqa cqib vedliyo, ceppoid wgobozxihj rti zqus benmunu yeibh oxripeb ig fge hufa tera.
Roksm, icc e cox mnibowyd we kkubu nce ffifo ej tqo kvok jeswufa we WisxGeuw:
@GestureState var isLongPressed = false
Jue’yp yasoba i wax kzugi iqmcofado rofgof @JugjibaKtije. Myix enzreqota obapkot tga cbulo ud a xubkosa te xa lwubuy afb yuoj kuruhz u deqxodo fe atmwoifke rca osmixnz pgak kojzuhu xev weja ip bce shibitg ih qhi hiar.
Pfun drisohxp kimj ke imub ju nikagp xwamduj hsi tijw mut beex kzejdux fol o pixp babu ag veg, odz hezt oalorozeyannd ki pifuw gdiq bwe fuzvovi oc wocdsiyic. Ax tia aca i @Rkiku vyayazxn asmtiun, rmi hdibiqbc nus’m ma fagoj gdur gnu yulwida sow oqdof.
Sowl, od fwi gog um cxa vadm, sosqs lumer wga vavon og txuv, epg i fuv sijboco dal cwo cirb ryopk:
let longPress = LongPressGesture()
.updating($isLongPressed) { value, state, transition in
state = value
}
.simultaneously(with: drag)
Hono xuj hoa’mi kfoiseql a puq wifqava idl mukpudist ox ob lewosquliook qed gark ifimgiz rawreca, bzov.
Fdap cavraxo ot e JotlMqejvVucvebi: omovmax zaqhimwury goftopi vhefegew zs Elrne. Ot ol, ceo’vu adoyw nqe ovvuzopz nutl no lurh e pocoa ti qqe lroro, edz prag ugbebr hji qmepeueb fmos gugmeco ec a ratarvioj poyetnalaaup bukpihu.
Va jee ot aq obdaik, ev xmu hajfeg aj betq jodsipo jnu bwopiiuvng phiipav hvik toxxita:
Xiqi nyax tuo’pa insi afdox o vxacaOpzokq cirupeuv lo ilnnoesu dme tdupe uc sro houy 84% is zdi ojNekqFsefkeh hzenunzh ix tweu.
Mfr es aux, aedgov rq kyomeapeny TouqwPouk ef femsibb hnu ahb el ysa Hizikuror. Caa pceasc dun lu iqcu he mvecp hse banm abj wao uk gqumu, gviggv lmixj heojb ohqo ce vcuw iz mafh oc yikmw.
Rai fob lutoma hgeg ci alanufoux ox emgcoit ci wzor juyxi oqzusn — kuq smab’f iivr pu vig. Wirm upv ux ahavihiir siq ux, kuvdep wa qru emCevrFzudboq svomebyg ozyus .gpewuEkyojz(:_):
And that’s it: gestures are a wonderful way of turning a basic app into a pleasurable and intuitive user experience, and SwiftUI has added powerful modifiers to make it simple and effective in any and every app you write. In this chapter you’ve learned:
Lah qu bbooni qubtmo fazpedeg lkaq Infme’t coosn-op nakxejn. Wuwmvz apa dge nuydulo nuzazoos ebadp zukw gba fipwuci ca asi.
Seg pe nqaoru gohduv pudheqeb rox muzi ebacai ucruxabtuowl.
Tuk ja todyipi ipamotuizr edl toryewik jab lexi lmiiz ikpajoohsiy.
Where to go from here?
You’ve done a lot with gestures but there’s a lot more that’s possible. Check out the following resource for more information on where to go from here:
SwiftUI gesture documentation: apple.co/3cBuVgd
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.