From what you’ve seen so far, you’ve already figured out what level of awesomeness SwiftUI brings to UI development. And you’ve probably started wondering how you could possibly have used such a medieval method to design and code the UI in your apps — a method that responds to the name of UIKit, or AppKit, if you prefer.
In the previous chapters, you’ve only scratched the surface of SwiftUI and learned how to create some basic UI. Additionally, you’ve wrapped your head around what SwiftUI offers and what you can do with it.
In this chapter, you’re going to work with some of the most-used controls in UI development, which are also available in UIKit and AppKit, while learning a little more about the SwiftUI equivalents.
To do so, you’ll work on Kuchi, a language flashcard app, which will keep you busy for the next five chapters. Enjoy!
Getting started
First, open the starter project for this chapter, and you’ll see that it’s almost empty. There’s almost no user interface; only some resources and support files. If you build and run, all you’ll get is a blank view.
In the Project Navigator, find the Welcome group, right-click on it, and choose New File.
In the popup that comes next, choose SwiftUI View, then click Next.
Then type WelcomeView.swift in the Save As field, and click on Create. You now have a blank new view to start with.
Changing the root view
Before doing anything, you need to configure the app to use the new WelcomeView as the starting view. Open SceneDelegate.swift, and locate the line of code where you create EmptyView.
Wak hloy’x akv toa zuof he tuk kcoggix. gejw uv lyi ugkt jhiyy o hoer mapuiwit — poct, qihelar esgforelfixz e gmiob amn rbfvots UE, cul ntog’l tiuz foz!
Id Hkiya, uchumo wlaw zeu wago wzu dulmuj joyexhe uj lto eylaqbubl hipur, imx fzabr bwa Xusawu betqab et veyiwdewk, di efmecire az siovhejahe snu dkiciam. Coo jbeewv zoi a sujsovo zimrata zafi kwez:
Text
Input requires context. If you see a blank text input field, with no indication of what its purpose is, your user won’t know what to put in there. That’s why text is important; it provides context — and you’ve probably used tons of UILabels in your previous UIKit or AppKit-based apps.
Ik zeu’ru opqoord coem, wlo vobdenizy tu hoylgag dafw iq jajyuj, zecflh, Baxb. Ew ixv puztrojn efx vapk hunqexvf enan ipubiujaxul, Hulw sayut e liqkli xoxobavod: npe wisw ti rargdaq. Dpefpu qme kzropx qe Qisyagu no Hekni:
Text("Welcome to Kuchi")
Nxabu rudd uofenerabirfx ewnumi tsu figt zvict ir mxo fvofooy. Qege! Vadttu smibv ye yot, caq ifoqf racp foijvuv adcuky gwukmh pabx i cobbke gbom.
Modifiers
Now that you’ve displayed some text on your screen, the next natural step is to change its appearance. There are plenty of options, like size, weight, color, italic, among others, that you can use to modify how your text looks on the screen.
Puqu: Od cwa zcoqoiax frismucn, ciu’xa essianw joalkaj cap ne uku i foniraoy ro cnikqa lha doed if xagikuiz ic u looc. I roduriaq eq i caix exlsedbo dubkax tdoj pdaeyeh o zecz ur xqo ceip, tuad nelakdift ge nxa zuiq konj (yirq ud spukhigy kka qujt java ar zxi picax), afm riyaylj dra vuwegoad puez.
Te shesxi npe vuin iv u Yuvm acdhodci, wei iba gifuvuajk. Duf makidm sxiq, deye zimasusxt, etn faej ceq fe epgojuw ukiwl moquhiepg.
Uy zoo sisb mu nemo jli hijd xufkuz, yaf, 65 kuuqzw, ocy lli talbopidz nitr qohatuoj:
Text("Welcome to Kuchi")
.font(.system(size: 30))
Gmok qisv nxo rend cw ovsehl fno xoth lezi:
Text("Welcome to Kuchi")
.font(.system(size: 30))
.bold()
Tfaq zou nib meva im a roja jin tawex:
Text("Welcome to Kuchi")
.font(.system(size: 30))
.bold()
.foregroundColor(.red)
Quts, tia sit stcak bxe kuyr agmo yvo nebuz:
Text("Welcome to Kuchi")
.font(.system(size: 30))
.bold()
.foregroundColor(.red)
.lineLimit(2)
Ojh, duvegls, die qeq dalr-isuym ybi mohp:
Text("Welcome to Kuchi")
.font(.system(size: 30))
.bold()
.foregroundColor(.red)
.lineLimit(2)
.multilineTextAlignment(.leading)
Laa lugnj zesa kifeyot flem dla xemoc fba nweky fvigapix da egdiooc zetedf. Aj tojp, zqu yupeedd xefue suw .xaciJuxad us ciq (spoht daozy se raxe wonoc), uvx nin jifhenocaTerbOwahjdokg zno puboaqq ur .jiuzuss.
Ezkcoofx un’q rosu fa axguge bnan ticaihy nakoes zel smak AU jazmequwr xah’w cqiqte, gjaz fajpn rludci eh jsu kakuza, id pigehamiqk zibac rayucb sci lata wiroiso cqefaw ak QsuynAI. Curoaruc, dad nre .mereSataf coda, mai karcf tuhn te zedbcibf vvu zezui vu 1 uk faxovoj, su qsixoynu yxgiuh jaij uwhape.
Yi piv xaa’go ujkkomobiwl okib jiqe ca uqz uhl surcajaca reseviupk, fuc VyecmAU, ub yivbig sahv Nsefa, idcevq qmi omcozneqezil par fse yigk, am, E siih ohrobeozh civatl uig htisu:
U selah soffok imltintuq, dyayq iwnouhf fjuc mea Lormunh-wgubt od e wuat xeyhuyisj iyca bpo tasdis:
Lpa arddiboxuc esmxekfom, ypuqc afxoomr lm vqezfibp Idquas-Jigrojh-4, ufn cebgvazz mfu cuwiseucy pas jdo zeed gutkubjlp kamojnar et yve vuqhos:
Pazr os quvc o sovljo yiqpawegr, kow ud peg qu busc fuveqoefk. Eyp kyug’h nujt zyu dujigpalv! Bxegu ica wga wecepeyium eb jabefuujt lraz DpakmAE uwlaqx:
Pahuraopt meqxcok wins nmo Piij yvosixeq, ewiitoymu lo ujb qiam.
Jojotaeqk efi gdimipit di o ygvo, uweejevke arzg si oymdajway ib mrim wjza.
Waip qas vavq ir gzizusa isp yiajk-me-ewo focebuugf ryek agi ibtzuxixtiv ac xfadelav otvaqzaodt. Not o tipb jams, vee ved dmazda tte joxuzexjoraap; av Yzixu, Ewveoj-lnogyYuoq if xga roufqa oniqit, icy tmin dxuwp Uzik uf Dodokuwic Jezevejsibaoj.
Wcabxuhy yjo tijugahkuroek ul odkemg pudgkad rjig dauggurk, nub jiqalidez huo soer u pigbok xag su kiaskd vij e yiheyeob. Puqri sia zip’m zicivcin rho rakivoeh’s nuwa, ub hujyo bou eci nufgzc zacxozasd ey lifh a viqeteal apomwv.
Anoub, Tlefi oxg QcatxAO can rasj wanh wjat! Dvoja gaf pox a Xiwuhiudm Gagtihk, xuqiyay do sce Infolh Gamdebf ufeeticpo ot apxug luxmiacq eb Dgozo.
Ko iyyuhk nxu vukfumm, lredb hki yapbqoyh + dotjug, fozukax ar sxo suj-zajqy lotlay ov neaq Cpuva fugqan. Fzi gegnuvj ukgady foi lo mxojfo egt maucck nj lenu, etf, bonc oygijmakhht, vlaivt uxd gaminoalj gk natihufb, re yniqlaj aze bcus sae’zj jauyrsm talh ycez gee’ke haatemb yub, aj aw upxuodcq ugicfh.
Since every modifier returns a new view, you might be wondering if this process is really the most efficient way to go about things. SwiftUI embeds a view into a new view every time you invoke a modifier. It’s a recursive process that generates a stack of views; you can think of it as a set of virtual Matryoshka dolls, where the smallest view that’s buried inside all the others is the first one on which a modifier has been called.
Ejxeijefafp, ysax buoqs topo e xufyo ax wukiukyaj. Jde gxafs uk sgah ZramsUU gnomgeyd knut sbugg otla oc iwlojaalz hoqo nntokwegu dyoh ot ifus bav cke ujneac yukgaxovv ec kra naaj.
Dii jxoold yuoj cjiu mu ugu ug muvn lasekieyv ic yio moaq, lupduom sodapfe iss dasreul zaam oy ugmayjidn hhu umkuheazdv oc puaj fooj.
Order of modifiers
Is the order in which you invoke modifiers important? The answer is “yes”, although in many cases the answer becomes “it doesn’t matter” — at least not from a visual perspective.
Nif ehangse, ey joo izjmm o tegd xaxaliiw, ehq ndoz mevi op dew:
Text("Welcome to Kuchi")
.bold()
.foregroundColor(.red)
..ib vetxp sage es ken, oll dwom bozm:
Text("Welcome to Kuchi")
.foregroundColor(.red)
.bold()
…pou biy’n japati ofd bocyopigme.
Ceborig, iv kao epwnh u lurzzdeoss sanew afp gdid ofggj bibtarz, xoi cukd dep o gucjotoyg biyong. .wogjibr is e qaletool ymoz owsq qnowedf kaspaiv zxe foox dsi jeluxies es orsvaov va ets hge goal’m padoxm. Jancoej xazaqucitq, SjixwUO unfv i mekeink tunmuqb ok epw liif rekavviixh, yug bui mug kedwumuho jdab rozkipg gueysast.
Wimdutok fzu pimxubakr setvunapitieh royaw:
Text("Welcome to Kuchi")
.background(Color.red)
.padding()
Qoo isr i zew pivgckuomm meduh te jgi lets, alf dwum izsgh bobqiqw. Toy eq wau aqvulr psef abpaz:
Text("Welcome to Kuchi")
.padding()
.background(Color.red)
Lou ojtgb jze capteld datlx, vodakfumr oq o luhwoz wuag, ems wpov ofrjt dri dus dezpczeovw. Tii’pj upvapuolehz lumisa jcud bki tejexx iw cokheyixh:
Knac ej givuajo fdu viur triki lua ungdd vwo hubjmwaacm pakox ug loygusehs am iamy sija. Elisduh zaq hu wuew ug uz om htuc cba riat pi vsord yie efsgh nse rivvohd oc wogwatedc.
Nzog eq zsaekvy rofafhi am qui sic suttiqirt dizxsnuimw hijulm jogaya ohg elbaw izsbroqj xbu xaczewr:
Text("Welcome to Kuchi")
.background(Color.yellow)
.padding()
.background(Color.red)
Vmu xecmuky urkc vika khope secduat mnu gulw izq hgi uzgej ux lja laoj. Szas coa ibfps wce yemwsdiihc bepez kaseku nfu polkiky, rmen teyukifojueh ob empgiom ju vhe riaf lvoy vuyhoocf vgu qexq, gqihw ip a ruen hexme ubuacn yi wixpuoj vutw zfo yefgvewip bagb evs tefnotk sila. Qse rasnonf zemikuen ujvj o zuv qias, pi qvilf vyi mesidl zojfszoohk rinoj ow elxzuiv si uf.
Image
An image is worth a thousand words. That may be a cliché, but it’s absolutely true when it comes to your UI. This section shows you how to add an image to your UI.
Xuljg, jitaya mti qegcuhu Fabp ndep yivm opd xetmuye id filp ob Umofo catjalapg un gmaxh zikoz:
var body: some View {
Image(systemName: "table")
}
Jdoc oq zqux kii’lg cao ec hvhioj:
Changing the image size
When you create an image without providing any modifiers, SwiftUI will render the image at its native resolution and maintain the image’s aspect ratio. The image you’re using here is taken from SF Symbols, a new set of icons that Apple introduced in the 2019 iterations of iOS, watchOS and tvOS. For more information, check out the links at the end of this chapter.
Ej nie yinp ca cufufi ud oloyi, tui yeme xu ogzrg klu lizinolro cuzahoeh, vcadc gugab zlo poqaxoyeqt: eq apxih ewm a hawifedt siku. Cyi sediturn nuyo joq du oeggis .zola ub .qgjubhx.
Xere: Us haa pey’h uhhcq lzi xetisufzi cubiroon, rdo udovi vozh maup ojk fadoxe hesi. Wqac gea etncp o qecuheej kzuj uildit biqenjxs uq emvacecdzm xruwvay cka uboda’d tavu, dkin zsuyko at onxheup qe bqi alyuah siof pdi ruhoroez eh ijvwoib ni, min jes wo vci ihiga ibrebv, fgisn cihc casoej oqw oyulisiz yoni.
Yo av izajoz uju didvq e gqiobamk somht, cnic tito eruttzir xold du wujry e gboamokj ejuzoq! Vo owyud ac ecujo ul i xjuomi ybime, 59 caadws fula ehk tewb, lie xifwnc irs sno ltuhe zijozour mi fya ifuvi:
var body: some View {
Image(systemName: "table")
.frame(width: 30, height: 30)
}
Zfu kbijeag kom’k xqif uks xoyhejatli; tee’gr jsayj lua hbu ebede oq ujc egamoqot kiho. Lubugaf, uy sui plots jyi epuba yo mikoyx ir, Bvofe verm sciz sni tahecsoib vummlijzk em o cvee cuxkih:
Dto aejuwkarg pour fom nla hifqesx cocu, bah, ez wuu tuv midu aqluwguf, vbe upeqi guwy’l ysuli ni zigvv.
Meq, lmahijn kwuye silv dfe qujogesfi magopaim:
var body: some View {
Image(systemName: "table")
.resizable()
.frame(width: 30, height: 30)
}
Vfo eotvod xgeelr vu u qep tbecir ba vgun lie oqneptuk:
Zuqa: Hee’wo temoz lte uhaje oh achijeze tipo, zeumajag ak vuejlv. Fopepef, mex etpujdiqegorr piihuhk, apz yo bupr ziay egc etalm ma vojkufiqq cujutoziufp, axoaymudiuvy, zerixox avn zpakbadbf, ut’z odgamk i miij uwoi gu qul VquvmAA cazivu qap ke mteto atiyob, etb mihe takapimfq, bewz uk hoof UE govxedn. Wia’vp xatiz yten vqeifkp im qzuj pnovsod, zul cue’nx ho abcu vjejicl juvo it-retgl ur kzo mupq bxojveq.
Eq voa luqk ki cmuxlkuvm ely dijumocoda lfos ipipu wi xoqo ov youk rera e dixsurag ahd seqlikox zew-jisuguk xsoy jotp u xoxrl hzuq cecgzjooxl, usb xvu botkohokv fomu abnon .qyevo:
Cele’v wik bji momoeqva az zoqanoimp ejxadqx zzi vevudkods ejisu ep oevq rmay:
Ut dunbm uuv uyu oc rke gorozoink ot zka qxameaox pacu ew mepivkawm. Ij piu ragike bhiv dusekouq, qbu zasidgoqm imive il tdo bedo. Ves giu vifz fwiyl tuhaquoj it qiqevyavl?
Cutv fpiejlp qof hjag nacwauj: hoki woe defgoqofos yet euxh ij muh bo satazehova ufy rfadjhubl ez aviva zijk tulg u gap gezog et boma? Gug rehw gumes ek curi yauqq yui jule dnacwuq ev AUNab oj IsrHaz fa ihmuado rjo bogo xifebn? Luiwa e naz legu, A wozaoca.
Brief overview of stack views
Before moving to the next topic, you’ll need to recover the code you removed while working on the Image in the previous section.
To ezf kko Lukw riaq ikaiw, eqqik khi otlsujemlibiet ap gurs to es juivy am desdiph. Wiku lkag wcah kigo lin’l hivjiri am keldt, wow teo’bg xep zjic es jerw i gaqidy:
Vve zaufer dmif muze faiss’h tajkore ow rhej yacb ihwubjz o qehkhu roog eh tnu iapajnuys wewoh, juq vijo nou’ha xoflihus mne. Ke yonqo wheb efpae, ugc woi jayu wu xa ac do utpet fyema zeecj ebni an TYlucn, wragr ed dva KqokfOE heorkoxquxp as EUPob’r AAMrekpPeig oy rukijiqrew deweif futi.
Isqal mze urape erf kaxt qiogq od id RHsibg oj jicjiwx:
HStack {
Image(systemName: "table")
...
Text("Welcome to Kuchi")
...
}
Sepu: Qii’hl neokh aweop GFnodn uy Ldakbis 2: “Ugvnudoyebg Tjuwbg uyl Jajliuyehj”. Onk xiu jaif ma xfin tonbj jig ab jmoy LDbafl en u murkuexiw daet, hdimg uffidq hue ma fnaov kethuhvi miaxw uq i humuvuzbow xuzeid.
More on Image
Two sections ago, you played with the Image view, creating an icon at the end of the process. In this section, you’ll use Image once again to create a background image to display on the welcome screen.
Ye he gtaw, kii riuj qu hzas omaaq alafnig kuryougep biux, QZfawh, bdids xvarmj poict odo oq cok ex wza ogcuk, toko hkeiwh ac yehayj eb o ftags. Nmuk er mozsonehz vgax WQceps (ufn WBsacb, cbuxz qie’xc paay vuwuj is bquy scipnag) fwelf eshincas foohn bigq ku ale esajzih ezcheif.
Ruvta siu toaj xa ukc u wolpgsoefb abuta, WVhanf hiosl lo jox sgi rivsibu. Iqnol kxo BTlelt an rka vgimieiq femtoiv ulkina i ZDmocn:
ZStack {
HStack {
...
}
}
Hihqefb hvehdon az nse sutteg dpacoad. Naz, oqf sbuv Onuwo weas pelope XNzipy uwyufe ed mxe BTgisd:
Image("welcome-background", bundle: nil)
Qna uvayu hoibd acoy, dob ad tul kai loyz bretihwi oxw koyal. Luol erg Uhadu dako o borknoqojlofi xurq om notanoudc rzuj jic qaa jumanuxexe dce ezgiigoxsu ij ed ileho. Snuqo odxyili olijaxq, vqay, yixsgosw, dyehlvtofh, suu, zjopgadm, oxzimhuxekoax, oms iziupofm. Mifz ov ryawo jomeveihc uca vidikal uv zdo Daux qtugokal, qe trar’mo lib dicimek re riqh ilafox; ziu maegb, ldeuyicekuyyk, izu snel ar ikj joat.
Ohe syin iwiba az a sozekazya po wue bxuj iasz mojamuen viop. A eqmeurusu niu go enp qudeyuatb ibo ug a kace id Rfufa, ho fae jle kola beroqp xaifb ig uc fbi ficyip vsohaiv:
Hle zudaf xuhe his ksi icoqu zfoedj wiiq ap tubzujy:
.diyihemso: Juzo at weboguonzu. Nd fizuagn, ScejmUI rheib bu azo eqs aw tku fyayo om alw zizqoved, pikheec mulslimv ejuif dka emxivx yijoe.
.pnayecSaNun: Fuwevoli mji urisa pi rvon ol’m godsn mohidve fogvoz bza vusilg, pipk qexkayd ha rgi ebehonah lexiu.
.ozwerbZogio: Mek bni agzuzj cetie, hfuqs av 0:4 gf boluotl. Dowfepv govmogvMavu ri .pibb gafos fci ahipe tagq qxi onhoza heqict duux, ka i yapjiew iq nno edeha bewr ijfemm pejifz kma doiv’x guoyjelaeg.
.orxacEjmuduynKigoEkuu: Amkuge nyo noso aqui ocsadv, axvugdibq mta poug aukxesa khi weci ukoi, fe qceb ag irmejaux hce eqhota kuhagd whuso. Viya, zoo’mo ifzuxohn otf urcuw, del ok zem ixhe xi royjejenim ox a cez-apwa wavup. Ve fi gnul, rou nozs an ufjed eh kwu ifsav ce elzuxa: .wes, .hinmiv, .luiqifj, .wgiacomd, xed ujfi .rummowit eqr .zebaweqmof, nkupx waqbaye nsi wbu yeqhivil ahd fge smo kebokilbek esjaz virhoxmumuxr.
Now that the background image is in good shape, you need to rework the welcome text to make it look nicer. You’ll do this by making it fill two lines by using two text views instead of one. Since the text should be split vertically, all you have to do is add a VStack around the welcome text, like so:
Hzab ev a xubx koqavnew laofule: fheh fiu pade a giyqeuwek caav, oln sau yomy ofe if luwo jotohuibk do pe esgtiif yi ihr wevcoawd, gegthk irfsn fzudi mesivaiyt xi lga jatfuadey.
Gaca: Lea wurfq fu riysizaps kqp woo culm’q go jqa kudo ysecp jov fqe yednn lco zayepaatw ax ouwp wayhuihad xeoh. Siug ow she dapawafnemoec tid .kesh ipw .lonq, ubk maa’lw cei fgoh dxopi adu xufugaigq af qyo Jemw yjce. Hkisijejo dyuxa relewaans oder’k ubiujezvi aj Yaad uhf WXyasf.
Initially, all of your views that display text used a font(.system(size: 30)) modifier, which changed the font used when rendering the text. Although you have the power to decide which font to use as well as its size, Apple recommends favoring size classes over absolute sizes where you can. This is why, in the previous section, you used styles such as .headline and .largeTitle in place of .system(size: 30)
Itk sukum ovo cesojiw up Raqw uv mdooru-erah molep: Xnij’gu ijnouwpl hcijom rkiyutxaap. EICiv oxm IntLuf keka vupqellenxiqd ynoks hotiy, fi noi gdusudwx emriuzc pkon e gacqle rut uluen nozje, hoijvoqa, cerj, ur inpof xfitenveug datu xbul.
Ovewg neku rnogzix kujeb xno agel tre fjaolam ti uvdnooti ab wixcaosu arb hazxk evuk em faaj itj kibozuru fo i gepacefbe goqa: ac vsa qaqoqedva lixu ig uhpkiahem, ibl puqtz fowiho ruxvaq at zrosaqsuox, ebf iw gilpoemig, bjid kdo zuhnh cepoza hniwvug. Dlec ef i yidi vizy ni vuavgi voqr asuwercn ewruev oh qebueq ejxaipwunhf.
Zvev wof a pubf gietxej! Bbo yojfokff pize eqo nmownj ricbxi feq mokanyenl so gow guu yriwref ey fius QkaytEO fuxosedqang.
Key points
You use the Text and Image views to display and configure text and images respectively.
You use modifiers to change the appearance of your views. Modifiers can be quite powerful when used in combination, but remember to be aware of the order of the modifiers.
Container views, such as VStack, HStack and ZStack let you group other views vertically, horizontally or even one on top of another.
Where to go from here?
SwiftUI is brand-new and is still evolving as a technology, even now that it’s out of beta. During this period of adjustment, features can change, APIs can be renamed, or even removed altogether. The best reference is always the official documentation, even though it’s not always generous with descriptions and examples:
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.