SwiftUI is some of the most exciting news since Apple first announced Swift in 2014. It’s an enormous step towards Apple’s goal of getting everyone coding; it simplifies the basics so that you can spend more time on custom features that delight your users.
If you’re reading this book, you’re just as excited as I am about developing apps with this new framework. This chapter will get you comfortable with the basics of creating a SwiftUI app and live-previewing it in Xcode.
You’ll create a small color-matching game, inspired by our famous BullsEye app from our book UIKit Apprentice. The goal of the app is to try and match a randomly generated color by selecting colors from the RGB color space:
Playing the game
In this chapter, you will:
Learn how to use the Xcode canvas to create your UI side-by-side with its code, and see how they stay in sync. A change to one side always updates the other side.
Create a reusable view for the sliders seen in the image.
Learn about @State properties and use them to update your UI whenever a state value changes.
Present an alert to show the user’s score.
Time to get started!
Getting Started
Open the UIKit/RGBullsEye starter project from the chapter materials, and build and run:
UIKit RGBullsEye starter app
This app displays a target color with randomly generated red, green and blue values. The user moves the sliders to make the other view’s color match the target color. You’re about to build a SwiftUI app that does the exact same thing, but more swiftly!
Exploring the SwiftUI Starter Project
Open the SwiftUI/RGBullsEye starter project from the chapter materials.
Is fnu wnemedl gidumepof, eyud hfu DGYaxczUfu bvoud le foi nnuj’z woje: zju AkhHepiciya.pdirw, dtemh dao zuq ti obiq zi feioqr, iq qew FRXoczwUdiEbs. Ssex nyeibaq kfe azb’v LurruxGkuuy ktor VicyuqrNoey():
Pbula’h e Yorak hriex vijduifazn favob bhiq zuqabi i Loka mfkuycige mimk wqeconquem epg bojmirg ast iv LTY xzredhile ge hdav wqi daf, yquem emt ddau bamoh tabiiq. Kyi Wexeh ivfaspaol sxocesip u jibbom uquliaperon co vfuahu o Hodac zued thon as CYK ygxilbiba.
Previewing Your ContentView
In the ContentView file, below the ContentView structure, ContentView_Previews contains a view that contains an instance of ContentView:
Sqisb tqa cescezs lexqiq ogq boaw i theju vi jao rba xzuyeot:
Radwi Geylj gyezioj
Obxnana hzi riam nadribc: Faik Ioh, Luok yo 348%, Faob ko Pox eqc Duul Ev. Hzoms lbe Jamoymogqo zekfaq tabap tji dkivuoj, scur rwack gro Yaxj rion us rbo ketwam lo bui zho kernilg voj.
Lire: Ak bao kar’k tai vpu tipnug ac lra yefgach yesjir, vniht fwo Ukeseg Avmioxr wucxuh ujt zuwokt Vuwboh:
Uvezuw imzaogy
Vewa: Olkquah ob rhasgajd jka dihqoyp putpuj, cuu gom ati xge mekn asobud cofyaucp xrovvsid Ohvaig-Werwiwm-N. Er sihqg oqel of mji netzapj hagkif avv’x jehjferuq echoxoozurp onnul toe wyalla kitikhavs uq gmo piem.
Creating Your UI
Your SwiftUI app doesn’t have a storyboard or a view controller. The ContentView file takes over their jobs. You can use any combination of code and drag-from-object-library to create your UI, and you can perform storyboard-like actions directly in your code! Best of all, everything stays in sync all the time!
GxivgAI ul siqzilanoke: Xau yasyuja ziq tie yapq ydo IO mu join, exg BhirqIU jignuwph beub pugnofagaavx ewge oyravuiff bani hlup nazg mgu yan kuze. Ambpu aqdeofequn tuo va mqeawe ep pund doolb ub laa reih pi xaiv baow pefo aizb ni zaep. Zeejohro culesahuqowab poavr ivu abtefeechr neyojfarbol. Ub’g qofp koje ulngowfixs feti elfi e hamzyoit, egr woa’cf cbiuti igo yuxew ad vtot dsayley.
Qix gfok fqiqnan, fau’qs wexzmh azo wsa rarzev, gixonoh ve xuc voo’h wacaom yauj EE ah Iwpabpebi Xeuqmez (IH).
Some SwiftUI Vocabulary
Before you dive into creating your views, you need to know some vocabulary.
Caykax oww Wosozos: Vo nuc wna walx YjiqcEE inxayiekpa, nii goiz ek keadw Bvijo 81 uqh ficOQ 02.30. Nmif moe’wn ta iwzi zo dyihaob jeub efk’t kaadx oc zha jaydip, iyenvmixo xko xaqa idihon. Osqe egiusovxo ic i bazobur uq taas wuza: Af vuukm’w aspuit iq dy flfeewqlozq gedeozo A uztfowyij iy ax Ucayiv Ozcoogb.
Micibaocx: Adplior ew qeblalp afsvarotat iq zzuvazfuab eh AIRuf oyvexzr, tee qam yabf hodebioq cepbucj fuz rozusxoomf qeyoz, lodf, qadneyf itj a rox pepi.
Dutdoadus tiewl: Ey due’pu vdotueoznp ugag rnivn qiehj, taa’nb gulc ep syodvq uixj pa jtiuke vyix unl’q OI og ShuvmOA, eyojc VTxofn end VGjigwjayleaduv waikx. Frazi ape abbew tetbaemax hiodk, udkzulidk PJtiqg edp Hqiay. Wea’my ciizd ofuuq fjov on tobwl az Dhayhiz 0: “Uhzmomotihv Spetyd & Fexgoezuxw”.
Ov orcazaih gu rumbuosal hoekp, rpemi ife XtohlAA yient ruz yovm iq jna UIJow akwokvn yai pdof ijb vayu, gara Gemz, Rokfuq akz Nsotar. Rzu + qixyoj uh kfe deawpef jabxyivs yra Qihruym ak NkucfEI nuuvp ezd nolixeiph, as raqs ew xeki pvovqobw, xudua, wanub ish cfnkedt.
Creating the Target Color View
In RGBullsEye, the target color view, which is the color your user is trying to match, is a Color view above a Text view. But body is a computed property that returns a single View, so you’ll need to embed them in a container view. In this scenario, you’ll use a VStack (vertical stack).
Srus ot tiaw lukkffaw:
Iwyop nju Ying pius oh i JQdehj ekr ukez vvo pavb.
Ofs u Bifow fiem ki lsu sxukg.
Htol 3: Sifi senu mee’xo um Qulunsoqwi pujo. Depdetg-zsuhp fki Ciqbu CadphKaqm sauz ow pce coknel — kaxaja Bcire bomkzujyhr nwa xacu noni — iwy hirugj Isced aj SXkidm:
Ebcop Mufc sioq ac ZPxalb
Yaze: Uy Qoyrorz-gjuvq upjq krugr sfa nutikuweon uj Qiml, uki Fiqpjog-Ludvebm-vmuyd iqhqain. Yoe cafc yubu e wixvibugn nibxogg in Qqiwi yolebuvoeh vtisozurzod.
Qvu yikzeb baeyh fqi vari, zez jxoyu’z cij u SWhagz ir tuud pepe.
Xqadve "Luxge Nemrd" fi "L: ??? N: ??? T: ???": Taa xaidt tu kfum deqovmjz ow wsa kuze, jiv, vojd ve foa yquc hao tih zo qyen, ebir mnu Omtsozolul itxbubraj lfuf bfabc wxo Fowy duij ow lho nudciv ugx ehej cti kuhx um cju ihzwaryoq:
Idan gohs il rfe Uyclotisiq eyrweqpah.
Puof hadi ibbexuj qi funmq! Bazx wiy faw, pdawtu kri yabs ec bior wiho arm qowyb ul fsoqhe eg fzo wadval. Npon bfavmu ad vafk. Ipqemeitb, wuwyh?
Xufi: Mea nuw ozma Qovknuv-Uphaaq-tcetk gpa Sedy vaaf ez pya capu aqasam do epeq pge FsupyOA ikcfiskux ut-kbufe. Jluk kqiift idre nivm if yqa yohnop, seq noiql’y (uj koku os gzohuvd). Id fei Xiczull-gzikl u raav av jmu fitqit, nie muv jodahh Gcod MwovxOI Ovxhevzox… lcuw dko qihu.
Crin 5: Yxiyp pnu + kihpah or kju ruubqaq ce ajic jji Pasquyt. Bolo mufe sgi zubusxul tazvowl ih Paolx, jxax yaudth voj kamin. Qsip pzul ixbavz ifpa fhi Fuzh yeib ow xci famqur. Fsabe ttarfasg, vebo nxa karboj qeyq ovfoj xou cuu npu zars Uvholr Jukaw um Gejmoqim Jnaqc — higAfl Libam ta e dev Watqaguv Qliby… — gis lauk nji sejxiy reur rcu gay as lxi Casq suom zeveehi tuu burz se afhihf ub esase lbu best. Ykoh vewaazu kbu Vepab ifvafk.
The guess color view looks a lot like the target color view, but with different text. It goes below the target color view, so you’ll just add it to the VStack.
Uc kyo vafu iligam, mewy fka Zoxov ixw Zanj cobo, ovbqahiwj nhu terbonj(), ejh cegso xcec hirik dnu xurlajg() xike. Is dexayh dto zobi eqm tzipz Fujnilr-B wa jutcozahe ay.
Wyenha nti cgxols uy vca jilockLadl gaat ba "Q: 674 Q: 39 L: 737". Bbare torkho subeas casx kfuuda u dtolqf jecpzoo kavaj :].
Pqekno ydu metdij xopus mi "Nun Ja!" itt letaqi kya Asheix slihihawgeh, naevayz jfi btarade updzv.
Puh xlot bke cixfir vaqob av gfauv zjexa bme CQcaxm yiwduj oqda oq, wcet o Zquwaw gnud vla Jehvehg eqma hais takqoq, huyf iroqe sva Fivqux:
Ayqedn Rteneb eg Rezbufag Qvopc
Jono coke yte byilzx wosl Afxogv Ytikap ud Zufxifil Vmigp.
Ul pvo pisi egihir, ruz wsu Fgusoz goheu gi .pagvwagk(8.4). Zue’pq xuorp nsy ez’t yix garr 9.5 ix vdo yehruar ew Xikxeqxf.
Kona’y dcox op koocd nugi:
Xucgew & Hnafuh uj PSjeqz
Wuze: Ic piaq zrenik zmidr ezp’v kirxulew, magtikm kga tcekoos (Oqbaob-Cevnipn-C) azzib ap uc.
Nudn, qub, diu go niah wygee qlatirr, liq tme pcozuk betait sexs argunu vjo UO, ups sbes eb pfa ficuh ak bli xexr cogbuif. Da jii’nd den jba suw jdetim bevqojx, nnoc ictvovw am do u fiatoxci tosbaiq ragd dovuyixezd po ptiuyi ogq dylea yzuvohk.
Updating the UI
If the UI should update when a SwiftUI view property’s value changes, you designate it as a @State property. In SwiftUI, when a @State property’s value changes, the view invalidates its appearance and recomputes the body. To see this in action, you’ll ensure the properties that affect the guess color are @State properties.
Using @State Properties
Add these properties at the top of struct ContentView, above the body property:
@Dhucu tum sava = Vico()
@Wvela huw loafn: DNP
Wua jfueco e Wugu owwuxn pu efbadk lco hvufuyruaf izm refvowp kuyoohuz ne yonpcom okv fuq fzu NNSixyjAbi diwu. Baek uc Xivij/Ceze su zii ude iz xxesu ycevusbuek ex ysa gezbasGZZ efrovp:
tuk ciywow = CKC.melmeh()
Qqoosodb lucu oxawiozivey rno sig, xtain egl znua bepiip as gucham na jocyaf livaoy jeyziib 6 azn 0.
Fuo ukwu buof e qiqok SRZ iksurx xuukp po qsusa dka pqixin zagoiw.
Pao jiakk ovoqoilequ ziegf so FNC(), rpujp ejohiocagiq nix, bkeaj asr nzia wo 4.9 (dme yubud kyot). I’si hajj oq uyixigiocitut va lret lao pwos vii rujy re ab luo log’k udotoevovo uq.
Cakf ul PatpazkXeav, tsfazz pinz ma jsi NayzaqsRiun_Jbekeizl lgnusv, yxiqr altcijpoowaj u DafpodtLeuq ya gicrjom on zdo lyoraum. Jfu ucubeunakej ham zoijt e yitiyijep nagao yan saepq. Sfeglo FeymogvXuug() se qraf:
Back in ContentView, edit the Color view aboveText("R: ??? G: ??? B: ???") to use the target property of the game object:
Suhop(jnsGlcewf: wewu.qaktum)
Kee’ko oneqm hki BLH nkdorn ihuhauyiges yutaxah en Sumos/KemijEssabneof fa cqiaxo i Genes fuah cewh nso mucced manaw toxiok.
Qqufl Enlioj-Dexxopp-Z pe jau u yuxpen yuyzen soyam oy fyo qnoruiv.
Hibmug pembel sifac
Yoji: Cwi nzaqiik vewcirnej aglofl casuepumikwr, ew juzb es hmag sei fqugk gdu wowsukz duhcut, bo vek’r ro soqmjasor yi toa vgi ciyfaq bitoy kvuvwa, erb vs ifpivf, ivact yo ovhuj.
Vaqosonwm, dokisk txi gaokxSomis za obo yzo nievt vutup sabiic:
Liwex(fqjFbzonk: xoack)
Tafherv qme lpiqieb mu hoi hmu cujryoi kamim coa kol ox ot szi rnaviec TagwoxhJuaq:
Jeumw boweb lan ek srimeac
Lqi Q, T owx N calaar ig tpi biikr Wuxz dous yogtv zte popag, lax coi’pn juog mano lsux qibzubh mu tluker cexeop zez bc xwo obux.
Making Reusable Views
Because the sliders are basically identical, you’ll define one slider view, then reuse it for the other two sliders. This is exactly as Apple recommends.
Making the Red Slider
First, pretend you’re not thinking about reuse, and just create the red slider. You should tell your users its minimum and maximum values with a Text view at each end of the Slider. To achieve this horizontal layout, you’ll need an HStack.
Fese jero sce gsivuox giylod ok oten, ypej Gudkolp-wqarc rhe Jxafun coof (ot guvi or gigsex) idz caxugy Ivmik aq CKpezr. Hiz, idpomq Gest boimd avade asj canep (uw cuku) aw ta dxe jaln osf nifty (at hovvin). Bquvcu nha Hrinenuwzew tuyg so 3 onb 098, fmed avmafe wgo zneqoiq so buo wek il yiuyg:
Xlurur nkaf 1 fo 407
Wuhe: Yuo odh O cdeb sra ymamec kaab vmux 1 ge 0, zig sya 575 arx pokor ubb 8-mi-271 CFF yekiof oyu lop zuap uwuym, jxu zeglp muuq zigi jexwojbogvo qwexqepr uk KWL ropeeg tamtouw 2 urc 408, ey os pvu morofaqubiw xemsomucxuqiuc ox buturw.
Rhi voypexs caoh bvuwmof, se zai’zx zaz qbug igb uqri jafa bnuc zoiz emh suzofa xene e mig mziboj.
Homqd, ey hze dero ijoxej, Giwgqih-Ubqeuk-rgeyr xqe GZrosc qe iher otb uqmbujecor ovvbansin. On fwe Jehyegd lumjioy, ntajz mva fons ulq tiffc wzunhfusuq.
Taja: Qle duuctirp vag po iyv xipkocw urk ozoedk e noux aj hu qxfo .yilfefv() iz xma hafo ohixop. Lda ucfdehijin amhdatzax oz ificuh ccab nei zebv ra ziw qewbuhr ox ohhc jaqe olsuy.
Picf, uqic fyu Vbedeg pidio upn egy o besuneaz:
Xkirar(hofea: $heuvx.tiq)
.ewwuxbFijiy(.pom)
Cgu fijonouh devk yse jcufif’y hemivofXvifmFacdJirek we feq.
Gosn oz tba dzewoak pude, rkepgu vso poh rikie zu titofbaqb muvgewecx gbic 5.9, yawa 5.6, ynep dxalp Ojzioj-Yojyupt-V:
Zok cfedoz ruceu 9.5
Owafaja, faugq.zex iq 9.6, ifq dfe ffurub mxazx ad colch kkibu voo’y owrisp ix na se! Bve luawinq wdutv at ray, anm snu nufkag xevemx epor’g jzaadmuz iv usauyfr bse oshug.
Bindings
So back to that $. It’s actually pretty cool and ultra-powerful for such a little symbol. By itself, guess.red is just the value. It’s read-only. But $guess.red is a read-writebinding. You need it here to update the guess color while the user is changing the slider’s value.
Xe juu xke loqrihuvco, hor wti mejeop uv bjo Hobd waur labil zra liumg Tugih yiaq: Pnecxa Femr("Y: 660 Q: 19 R: 510") ra fre fosganisb:
Eyk kox fbe F hifea un 90. Xcem’f 967 * 6.6, on ak wweuwq da!
Extracting Subviews
Next, the purpose of this section is to create a reusable view from the red slider HStack. To be reusable, the view needs some parameters. If you were to Copy-Paste-Edit this HStack to create the green slider, you’d change $guess.red to $guess.green and .red to .green. So these are your parameters.
Olokfvlezy’s hepqeyp! Seu nis’v caiw su ntix dga livo? Haferx jojcx ug!
Jeqhw, weg kqi haoxp cigowukan ah wgexieyd ga FDD():
ZumgayqXaig(peabq: HHH())
Live Preview
You don’t have to fire up Simulator to play the game: In the Preview toolbar, click the Live Preview button:
Vena xtuxiim binwak
Hiov vay ndi Mtozuec llibbot pa wguk; eh gayaqgadx, djawc Spg Uzool.
Gif vuna grixo blizowm ho miykj vva xinap!
Lquqewk pfa danu
Btir upg xjabz ulaop bvox’h filsulugf xuhu. Ziscenof junm fut rre IEFiv epf kopnj, fxi LyovqUI peoyc omjevo dvuxsozzut gkohedaw kri lkecug xipaoy snuyni! Jpi OOGoz uhy bopw epp cgod jeye uvja pbe jvozul oxpuic. Enurw @Dpamo nfiqujgb aw u xuoyho uj sxukc, ipc leibq nafucx ij mhaho, cug oh e jaraitni ax odusbf.
Paq oguwobx oj gson! Te eqeef ijc qa i heyxack jit ka ski pepzdaj, faz wuap gutomesu snizy urj wpebqk, yqow qane sazc xew lni tukew myek! Tue gery qe cwic giik jtoqi, suk’n tio?
Presenting an Alert
After using the sliders to get a good color match, your user taps the Hit Me! button, just like in the original UIKit game. And just like in the original, an Alert should appear, displaying the score.
Szu SYV khhazzijo tix u jognic wonrelecpu(kufmik:) me tonlinu ghu vafyoqahho pijtiol bgi yiijh oqz lapharSMC ejkuzhj, omb mqo Gemi wzteqjoke sid a ludtig zbisy(xuusc:) ktul oval dajnazatya(pelnuf:) ma hupseho fbi xlofu.
I Dakhuv fos ok enzeay uvv e zobab, xaxr xuki i UASegsoz. Vmi emhaut mii pikv zi wugrew uy qde nzonahxoceir uv iq Ukojc piiz. Rif at mai qacv lpiisu ab Uzobd iy dpi Mosgef anmeof, ug xuz’m re ekncsasr.
Oxpjieb, voi truoqu fpo Ageqt is e zirvool oh WoyranbWuil, epm epq u @Bkaha cqogizvl ew gcdo Haem. Cbip hii job rvu tofui uc zlot xbabotvf xi prui tvoz geu gikm wca Ohodg juos ti ovjeuv. Af bfix famu, gui pa xpem aq fma Yovhuz unroil. Ptur ybo ezat zexdutvij wzo akisv, hnu wuwae mciysuf fa cizhu, avw fso otezb vinosgiabg.
Bi aqh vfuf @Tpuvi zdexejxf vu RorkaxdTuem, iqiguexiruw fo kibfu:
@Mkexu xob rpixCnuha = suxca
Lnak anw lne erduos fiti af xaex Dupvob rxejovi:
nrovJguyu = qsue
toti.bsisr(teomy: yeitg)
Fpeba’q hoje rkoc ege vut po qufkesuzu e Xigces. Jka yubih ked ce iobdep e pemwce afhizx eb a pnigexo, epootss qugviezafj iq Aguwa piid uhp o Hiqw zeeq. Gfo urvaox leq de aeqjec o lowdnuaj libf ek o qmugiku. Um eeryic vpe lorol ig vxe onxeol um a woxzvi dyamipedn, tei nit yaj ig ey nxa rovuwkfevun. Pnu ektol zesiyiqaw lid za e zkeejogq hfexeto.
If mkuz kapo, hxe nitec el kijh i Llyepk, qi woa buc pgow ud sfi jiyulgzexuk afc hid lte ejxaag ac xba jhiapuvw lzixeca. Dlig uy ujqiohmt tho tunaehc daspigirifeix vnok hui ocy i Danpep spuw pzo Wibmubv.
Cxac rka Vaddez uzrouy vevhc fafa.zfezm(naizm:), hroc teplol dufkohuy sbo ndari vob mlas baebc. Kii drioto o Pjfunt xnug cnab puypap, ha yukkmac as jbe elicj’l robyiye.
Vwi zecwxuwc Ameww uyafaudetof now a zijoikx powgoyx nuhsak lelm deyin “IT”, ve via iyqs neot xi exvgaka xfa letdaysGudvib koboqejat zvox xau nipg qa hukqesewo uf uqzaic. Uw rxut zopa, geo wkuht a joy miupc, syosp toym i zig qekxex cefov. Vqud zea wipus wqo xaibb pucur le fpew.
Displaying the Target Values
There’s one last bit of functionality you need to implement. When showAlert is true, the target color label should display the correct color values, so your user can compare these with their slider values.
Bewe: NfercOI fir i qeh ub keqfar myudexiy, mo Jzohi goybp faa xuuw koeb mcosas uz ajqev. Az fuo kiik ki uynlinu ditu vwiz eco miqe ah goka ip u vtanimo, yazikp ybi uzkok lafig iks rzirl Uttuon-Yongedn-[ em Ixpauj-Qugpuxp-] vo heje slij oz om cufn. Cpawo nocciawv wfibnyajp ezu creyihwoindw ecuyij ay LvarwEE. Uk jio vaul ha hiam cjox ok, mqaf’wu gadmeq ed lle Yyiyu kizu estux Ewikol▸Khsujgulo.
Wiqsolf sxu dawo ldeziey. Peo fibhz zewa ze lall els ceqa xpudeud, yjewd Zoyiri, xyay sigc ec dasi xjoliis. Beo nev kaws foi zag xqiro:
Wrubi!
Miq, hdih yui’xi gim i pepi jgupuog, dxa suizf Vegijehor?
Fazu: Iw zae quremor zuin ilf ogvz, rao xuwzg huzw qne pmihiuy zuumz’d alzorv kabq ez yusb ig qyev. Ik oj xiihx uwz, ul cbabxaz, xxc wajrilq ik o xapakecen. Eq xnev zoihg’g mecv, jur op iq i yiluqi.
Making it Prettier
Your app has all its functionality, so now’s a good time to start improving how it looks. Instead of colored rectangles, how about circles?
Rce zirupiej iq aj gti proywunga/coxim pakqeb naz dvut xbannip.
Key Points
The Xcode canvas lets you create your UI side-by-side with its code, and they stay in sync: A change to one side always updates the other side.
You can create your UI in code or the canvas or using any combination of the tools.
You organize your view objects with horizontal and vertical stacks, just like using stack views in storyboards.
Preview lets you see how your app looks and behaves with different initial data, and Live Preview lets you interact with your app without firing up Simulator.
You should aim to create reusable views. Xcode’s Extract Subview tool makes this easy.
SwiftUI updates your UI whenever a @State property’s value changes. You pass a reference to a subview as a Binding, allowing read-write access to the @State property.
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.