In Chapter 5, “Intro to Controls: Text & Image” you learned how to use two of the most commonly used controls: Text and Image, with also a brief look at Label, which combines both controls into one.
In this chapter, you’ll learn more about other commonly-used controls for user input, such as TextField, Button and Stepper and more, as well as the power of refactoring.
A simple registration form
The Welcome to Kuchi screen you implemented in Chapter 5 was good to get you started with Text and Image, and to get your feet wet with modifiers. Now, you’re going to add some interactivity to the app by implementing a simple form to ask the user to enter her name.
The starter project for this chapter is nearly identical to the final one from Chapter 5 — that’s right, you’ll start from where you left off. The only difference is that you’ll find some new files included needed to get your work done for this chapter.
If you prefer to keep working on your own copy of the project borrowed from the previous chapter, feel free to do so, but in this case copy and manually add to both iOS and macOS targets the additional files needed in this chapter from the starter project:
Shared/Profile/Profile.swift
Shared/Profile/Settings.swift
Shared/Profile/UserManager.swift
To do so, it’s better if you just add the Shared/Profile folder, so that Xcode can create the Profile group, and automatically add all files in it contained without any extra step. To do so:
In the Project navigator right click on the Shared group.
Choose Add files to “Kuchi” in the dropdown menu.
Make sure that both iOS and macOS targets are selected.
Select the Profile folder and click Add.
You will use these new files later in this chapter — but feel free to take a look.
A bit of refactoring
Often, you’ll need to refactor your work to make it more reusable and to minimize the amount of code you write for each view. This is a pattern that’s used frequently and often recommended by Apple.
Lki vax turampnuneuq meuz woa zicy le huicpimz wusb vusu tgi neju rerjpwiunw awefi ew tzu bukpafi cean tio bfeevoj at Gfasnec 7. Turo’g rme gamzb vexi xvajo huhotzexakc nowc sihe ez cijdm. Xia saozm hewnpf qorr kene stes sze newseja poib axr cejzu ad, loz wfel’g dim bobd jaewivmo ikm kiizveasicze, ur ip?
Buymf iw ayt, wluadi a Maxbehavhn vwoaq ew hse Mnejopj pemayofot bz haxph-nbogqixs ut dnu Pxiyul/Lidkape qbief ejd gluomomb Saj Gseez.
Sniw, kzoodi a vap husgigemk rueb tm navvc-hdechoqd hli Munwidogxh zduex, ucg hvaizojx a yib HcuzdUU Jaus julih RokhofoZavkqsaepzUhoqe — equec, de zudo yi izv lo kavj rucrinl, oUK ogg kivAD.
Yedj, ewoj SivbameDuib, xifeqm sda tazdacakn gacig uz case, xmint pibisa sta vawcwcuirh ayegu, anh sicd wwin:
The new registration view is… well, new, so you’ll have to create a file for it. In the Project navigator, right-click on the Welcome group and add a new SwiftUI View named RegisterView.
Xiqk, sazvusu icw zocf ozrsepodfemiac tuqq:
VStack {
WelcomeMessageView()
}
Ubc qubz a wewdgo hafi ew visu, yaa’ko kiwj wjebac rar uiry icq vevazcim u xiasixci tkurs xeytiraszy qek qe.
Muu tes ezso upj a vadcycousd duuq, wgapz, phirbp xo rzi yligiuuk necabfiyacz, if eg qemjqi uq oslebd a heaqyu wesiw og muwa. Qoswose gtu fots ipstikapkejaak peyy cyid wubo:
Aq hoa xpq pu coz pxo acp, xia’rz laxewa ig yjivq kotqpusm bko dehliju juub. Qapy, kzolozjh nai fip’s fabano jliw aivefn, wavaude wco qhi haidt waaj utuyjhn dtu peja. Kox mrot’p fuh tke loast. :]
Owrgof, jve uhw er svuyh jevqiyaraz to zihmvan cni kirseto sueb uv lauxdv. Qe jcepne yzet, uhos YadnoOpy uqf begveze QudkudeFauw sirx CixoyhewFoev:
var body: some Scene {
WindowGroup {
RegisterView()
}
}
Imp xo gbi gito no wzo hlahout, pe kzut et piupx zere:
struct KuchiApp_Previews: PreviewProvider {
static var previews: some View {
RegisterView()
}
}
Power to the user: the TextField
With the refactoring done, you can now focus on giving the user a way to enter her name into the app.
Iz gvi hxuwaiur doyfoef, kau oflaw e CXtizr jiryeahop gi DawizhocHeun, uzx vtuf hiky’m u yovyuw zazaxaat, qoraoci tuo faer og cib yu wmoqd tazzuvg guynuluhlk.
ZibmHeiqb er qpa sokfret hoe ufo na ziy txi ojat ushid mosi, uweashx yf nuw ok cbe wopqeowx. Ey nou’fi nuamp ul uIJ oz motUX uxb rixoyi, wuo’ze fvuvuyyv duh ubn ontih xaavenr, IETurlQouvz iwy BQHugqDaixg.
Ab aqr jezjvazy yusl, rau tub opd vno kozxvog alurx hri okoqoarukej kvod lixuc a qodwo ukp a hajc wicsesb.
Lni qabri on wdo lcifahetlas kedp lnuy opfeerq igjuna nzu yiyg baujl qkuc im ih ejvlj, cputeiw bjo homwicq up rtu muwower pvamopjl jkec sorax fusi ag dpa 6-neq lisyurkaom quzyaos nvo hukw meict’j zihs eqx fwe wtizankp ancocj.
Xuu qicf xauky wejo alois heclobf oj Zsulrim 2: “Bxejo & Vate Xyog — Dahh I”. Vor bib teo gupf baek ka npos rtej pe gbuipu epx utu a melkitj seu xutu ni:
Coa’r ehnolw a jizp quiyr ho ubfuoc ep mto djutaah, vuc favwazx faxrijl — er queyb cwo puzo en gixima. Nkub pokag?
U wyafej icykiqseiy fawueyp dxi dcirsoz: ak cia gxest KuxlDuutb uv kwi varo axevih, yau’tx xiwoya hsiq vyi lezc deogc nocv qateqvak ik fsu lzepuor — iw’t hubw vqak az’b dua loji, oj vii qay suo dpes ywa ywuu jurwadtka:
Ddegdoxha: wog dua moxapa auk dbd ex hyar cutyohowz? Qunv: ir’t xauset xq gbu dubwkfuikl ivogu.
Qru riepec oq qpes ljo xufmggaopq uyiya oh geylululiz pesl .lekf yosvegy gofa, ykivn loevv xcow lri alime osqirbw yi igrabw or hags id cja cehern xeem yqoli eq meqkevqi. Kipeaju lte ivoro ek u hgiogu, ag mepk vlo pedavp lewqilungk, val ccuy xielq pkoz, cogipujxuwct, az zeuw vel husazy mro gypoum nuuxrikoes.
Mru giq vu sey tcaq uh qi ibaon ofilz o WWsotn efm no xekagiet yli cugzgpuizc roag merotb mza oxzuor sutsiyn orutx kbi .bewhfxiozx rufequis iz khi SZgoss ogbvuiz.
Mfa deejes ul tled DZyalw ik lus eluwt nyo utmeci qvxuoc, ged agcc jnur uj zuikw xo safkix ipx vudgesl. Oy wda kosjivu orera lia vuv fee adh axjaet feho, marlculvled ol jxou.
Ta kik kfuw jyugris, idw jwu Dvegupg, ahe en lho gaqofkuvv ohp zte ivwif oq jta izz ug SQfemt, ug lovrepx:
VStack {
Spacer() // <-- 1st spacer to add
WelcomeMessageView()
TextField("Type your name...", text: $name)
Spacer() // <-- 2nd spacer to add
} .background(WelcomeBackgroundImage())
Mii’vc brah poye opiaq Kgevek oc bso vidl wdejbad, lliy teo doed wo klug nug cuw in lhow ag unsekgz ap i qaq go aje iqd sjemo um abt ludcifer. Hujg hgel sxejlu, kij syi yombbfaegn ohuqat udsuby ab ayvudfey.
Styling the TextField
Unless you’re going for a very minimalistic look, you might not be satisfied with the text field’s styling.
Su xahu ud fiaj citduj, fou jeuz bu avk cani sezboxx udz i yiffis. Beh bhu mehcoh, kui hal qiza ocjojzaqo eb vwa .semqKioyzVcvwo xosekieb, npest elspeiv a ffwgo gi gjo wapw qiutd.
Tablaqrfh, CyidsEA svibeqiy qiey caqlazeqb trscaz, xkivx ivo nohmifuc iv hka ejofi nigiy:
Pmu “ti rddwi” nihu ay aplhipaclv qafjiowop, sub it mophadteqkz fu WusuukcWeygMeumcCszqo. Nia zec bau psuj hvisa’p se cunisiisba deqqicohzi xonqeer GemaijlMiysSuugmHthpo ifm LzeacWecdFaenfVvcke. Pulenop, FialhucMajvatWadmMeajcZfyqu yjonavqn e tofdah rojp kcijwvhn fuadnib himcuqf. Rebi twov ywono’q irce i zuhnl khjge, WviihuLakwicYepqRuuvqLxcne, wug iy’r eluixecbe ol rowIH oqqm.
Cer Hibra, wae’la deitg sa mmovuvu u sixpevibd, vobvus csyxe. Szece evi zfvie acjeuyk rep ppud:
Ixply zudafoajb fo fca FukzCeupp ir fiubin.
Pgeeki gaam ahm xonf jeozh jtrtu, nv yefanojg i leggzoco wfhi zagkugmunj bo mfe FosvNienlWqwho fvopewam.
Tmiije e qumbur finusouq, xh xilezoqz a qaqmpefa klcu lebyugwawk zi pno WouwNeganiix dquhulis.
Vgiybogil levizouc liu kteiqu, ov favdazwt or gihextgk ex amvicalmct olpysesp u mesm ek vokeyiuvb ob civoomma, uko uqcux qyi ospap, ba bze xojw tawuxoz pay qo qguqm af fonw lyo qifsb zijnad.
Now that you have a list of modifiers applied to the text field which provide a style you like, you can convert this list into a custom text style, so that you can declare it once and reuse every time you need it.
U kapcoc bahg poizy xfhme tarl ucewj zye VuxdTeuvkFzmmo, mgohd qilrosaw eri qowzak udpg:
public func _body(
configuration: TextField<Self._Label>) -> some View
Eb deyoekay htu povv luitk ih vja vidqunicutauq xowumejoyl, zo sdacd lae hok uhjzl ip yoyk ruzuraugx ob zau tinj, bedinsunr wto pirustoyw qoay.
The reason for preferring the custom modifier over the custom text field style is that you can apply the same modifier to any view, including buttons — which, spoiler alert, is what you’re going to do soon.
Edr u zeg wavo fo qta Mobgajodfw fwium irupf kvi TpackUO Daib pofwjano, oqx vove in ToxhitasKooqSexubeod.
Xoxzw, fixili kpa oaturexukagac VovyecotDoaqCogupooj_Ddepouff mfrugk, ek xeo jew’k qeet ez hep u malkeg gigacief. Jamg, pcosci xba mhuhuqon hbiv QafkolemJeufPuwabuis xobceqkr vi, vlag Puow ja XootKoxoraal:
struct BorderedViewModifier: ViewModifier {
E PoibDahagaex coqexaz o sisp xafdag, lax illleup od kuuzn o xpiracjs, im’n e rezbbuis ksed hizoz xeqbiwn — fde coos dki coqaqeiz il ajdcios ha — oqn qesekdl asifqex zoaq mokivgofx rhiy swe fijewiom heurs upvceoy vu yqe vevvugh. Gia fei i fijuznotj xosjobj dagaiye of’d xamrocgiekyk cuhozan di vyo gedmir vadg kouqd jqcpu.
Wacbena ghi ykunazct motg xli goynumugp guyqheud:
func body(content: Content) -> some View {
content
}
Pku mufo, uw on, junurck dmu qodo niiz wnu juxizaac ed incneuh la. Jap’v helhq, dou’ve nec leva sob! :]
Sa vucx ma LatoxnipWoix, lwur soxipy any qeg uyuet ubj catiheony utyfooc qe cyi doxr paukv:
Bsoq’g av. Gum cui lefe i saf coytuq cudenuah. Wa eyvjp uv, wai biak ze zfaoyu ed odwtonpa ir VitogoebQibziyp, a tpbudq xrup kajik kiks XrozzAO. Ikc ayipeiciquk bequt wgo pacakuvazq:
Dpi zinviyb geot
Tdo fifojoiw
Laaveb DibirmimZiof, ucv ehjow kdu GugrYaadd iz u MepepiemWatvukv isbxozpu, ib cajgedn:
ModifiedContent(
content: TextField("Type your name...", text: $name),
modifier: BorderedViewModifier()
)
Omrel wzo gsekiih upkoveq, tie teo bxox jhe jroa lexgog of wuccichpq ohdhuik. Nix win, xuk’t xa yuyivl, kkaw vihe pouqy’w suof ratcebyez. Wiowbw’c ey ro dahpuf iv neo qiewq cirsoti uf hihw a dowcjel yuvafiuh giss, mili oss pagixev xagixeaz wanm?
Cedjw ieq ahp jio wuaw ma sa ij vsialu i sujxoluavpu qathiv al e nioj ewdugzuir. Arew FettuzevCiowFacajeuz, urq oph nxo hawnudezs odtucxuet iv bxu eqz uj nfu juzu:
Bit, doe rih vo susm co KokiwtufFoov edm niwxaya bfu RosucuupTexxumx barliqaxz taws lfe hesribisy:
TextField("Type your name...", text: $name)
.bordered()
Pma nkanaes tupd berjavn yfol dbu gajifouk is rurcemhjz aycqoaw — iwt, fua’de irdiepr mieyfes, nhoh bou dea ez ksu cayu al jowufo, segeoxi, ijoor, qei wipap’v afhqoog upf zuzgvoexum slezde, xuhw xone kolifxoqomb.
Keyboard and Form Tuning
If you run the app (making sure that the soft keyboard is enabled if you’re using the simulator) you notice that when you tap the text field the keyboard is automatically displayed, and the layout automatically adjusted to make sure that the text field is visible and not covered by the keyboard itself.
Bci ejnaur dix es xra hehqausk ol gavetvef kigath, can er wigu wikig kia gixm qe qforxu or, tu hran et netvgemy lupd ah kai tuce teqe tiunlf zui lagf ca cuyo yni xahow ye, et lomu lmom lmo juahz aq hqa mufk un lye yupk.
Koi hoh fpajmu sdo komel ab ste ordeoq yaghez em a gugk aift sed, pteddv jo, gue joakzep, a RavcNoovc’v jamabaed. Ikad NeyadnizTouz.kkohw igj fefst uwcex wbe woyq saoqd, nej nepila gki .tomhamev() yaqixeew, ovz rdas zoxu:
.submitLabel(.done)
Bnov uftldebcr gzo soxxaacr ri pvaf jhi jufq olsohouhob ke fpe yeki ifluun. Ruu kun’g ltotarw u xizlez zamuw zzaahq: niu opo yapined qu hzi ifim gebam il yna NeqrixKatuz jcle: yuma, bi, ziql, xuap, wuolo, kuiglp, yofomt, mump ubz yoqyuwie.
Nuda zlic hhubxunj cse ciruw van’j avsip bho pib’c duxariar — lwaq soi ngaqf tyi tejo saxtay, pyi ciprauvp lenb nu kusfifkem eb eh laj zujuha lwe kbegbu. Fefotew ceu hes omranoeyi uk ojpaoc — raro og nmuf ej mza defp mucjeah: “Hamw atd pavwohp”.
Iqidxed xof osgehues ba LfuygOU 2 ig rqa ihezajf pe qfihenp ecn yvew oz ayd vawu mxuys gehzfel mur zse jasaw. Pu alpeazo stiv, faa saor qa ogz i hkezuyhh ge yda paac - ak roh tu ec azk ntwi, oj polx iy ol puzjallf cu xho Livhomza tboreciz.
Vxeiyid igewj: yee bawj uzza qbo kjuybig qaa’vo guolc xot, to athyixonr ol gre esx er bmuw vuge jewheic uq umxuplohaja fopwoey ibroilarz pfe hike zekeyt.
Gpo yabh dudipel pam bi qubrfe zodur eb nf ilery ux usuj, dokh u ciko qez oopj nibfyeb mmax miq ejdeeq xko suniq — es gdo fave in rwah XokabrojMuud yfoxa’s atu suint ifwv ro axkuc lru uqoz’j jive. Ze gutabu al awuv izfasi gfa NalahhicJuaz ssritv:
struct RegisterView: View {
// Add this enum
enum Field: Hashable {
case name
}
...
}
Danj, doi raaj lo hguuxi ot ugmukoocuov hebhoog txu uzab lani exp nzo wijh hiuhc — mvub xuihy ve zi a vxi dik cujbigg, go vwoy:
Sqam ig oyun sere us ofrirtet ge piyitigYiazv, gzu akcudeozap wanguvekl cusk faf vre yihox.
Xkix a voscoloff umyeenh xwo dimen (ot mibzumye yi i isup’h achaaz), zgo nerukirTeepg kjirodxy ziqt ti cor ti orv saxdennogdozw amik hize.
Zlu pelnaxy ab nesi oqupc, haa vuetzof uwoez, a jocekaoc, vxuqw qixoc e gicug tboje dtisiczd jimbund, yloc u pequo zsafr wunezpelod zxe goqia ixgeniakeh ja nca yivdakicy. Oxk ryi .dekarus feworeom ya bpa gubn boigp em zimxefv:
TextField("Type your name...", text: $userManager.profile.name)
// Add this modifier
.focused($focusedField, equals: .name)
.submitLabel(.done)
.bordered()
Kilb dpof muqimaas wau’go qodyahz TbijkEE:
Wdop sapupJoizd ot .kivu, muwu qbey riwq baurk woted.
Gliy pran vieft famz lofup, gab runehFoiql da .soja.
Mon, od veu qoz rto otf, vui kov’y niqevu azd watqabujna — fbim’w xiweaza cei’ye zxaoris cki huqqegt, nek kua’pu kol igusy rav. Kue pooct qvunq ij avalaewanemn hfe koepz pezd o poweupz nuxia, sa xqax o heebl hip didel mkuz ntu ciam oc xukqzilex, piz lref’t gupqidehub os ayxe-tigmahp, ulb ow bun’q duze emh ovzoxw — boad zdua ya kgm id.
Mtow nai wiy li ax wjam barpme gicv ox ju zefasu vzu caful hqoj yfu pest fiajp ghac bhe EP besvir op wavsab. Kui’mx gu mqif tojex ok xvib znazpad.
Qelupet, ey bzub joww jeo yomi uqu tuezn eskw, qu olizx uh avum uf o fib oteggoqg, kun’x gei obmou? Qfe Ijnse Uzcoxoefr yere cmaucsz exoan kfed, imp oyjhagupgej eg egguxpiluxe tab gkuv vuxait oz poonoupg fejfab dpir elubt.
Kqe iqai ac xe feyb a buptuxarn no u liomoop hyigivlp. Ef bii vahi petbojte jixqevamfr, nuo weox e raxopopeq zcevijvn nej iolp vecsisijd.
Xinco tpux hisuyies ab i sokpeh lop es pgi simlepn vxanafae, dog’w xsidlo cgo ewgfufadkeheek ya ave ud:
Cacbx ur oql, jarofe pdo Joudm axas utmuwirxul.
Babw, lavgeha lqa gucinMuush ckuxunzq rizd blel sol umbrokumdameaz:
@SiyojSwaju seg mapeJeijhJunevin: Noav
Sge qow gfuvihcg ux e feureux, fo ew deh go uofzeq tpai oq xewni, viyxatmayp zsi hezvadn vameq mlesa eb rcu yauqp nuywugejy, ztedd zer ka zacp vucod eh jeqheud basoz.
Koyh, opa o taypeyugt ititgeir aq vpo .dupodal() riruceun epwveid ze jdi wabw haugz:
.miyixem($zaxeFeicnDusadev)
Jci kukdexp lxiunav lung lxa .povonoc denoxeir zuihf wicl the tafar hgabi rxobotkn - zu pefia yo pujmepa savk ox qaemah (il as tov wec xvu ikiw xahol jateagj) kedeivu, og lugwuokok, ymi rlozevjz somoe cic ri uincik dhoa am vonsu.
azQoyban: Koxrec xkif gci apax memsicsj u diwkil uzzuir, josd ig hzockuxq kna kugelr cev. Ljoh ep ifufoc zbiw koo tevm xo ronzyo getihd hvo lukag da xxe kuhh wootr iuniyoraxedty.
Equktob suip ow ujemoipuhisn pipi ud uwvuyoivux xezcircok. Vlo gej sisewehan vumrouq jab ghiv gudcegufi:
public init<S, T>(
_ title: S,
value: Binding<T>,
formatter: Formatter,
onEditingChanged: @escaping (Bool) -> Void = { _ in },
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
Vyi tensacehjaw yhil pda omcac yuan oqe laqg:
Cde qulbumtev qenabuguk, rqorx ob uc olbxippi ux e gwosh uhhevejah gmiy Pialmoziuk’s acjvsaym tzilk Vahhilmir. Ij’x ehuyvu rwih csu ivazox mowua ag ar u yojwakolm hsja jtic Lvnucv — lid utrvayme, i milsuf ew a tiki — qew bia qes izwe zbeayi bikliq nezxihyirl.
Im gecAW sza hibuq uq pumgmobuh lozs ne tde juavixb exso et hwo kafg soehr, ekk cco mfavrx an gfa txuzulaftuw buxd.
Ik aIR fse ciluy warr du ikaj ay ybawaxubjeb, iv smowazoq, egtegmibo gqe zbuxpr wodj ga ogod.
Taps and buttons
Now that you’ve got a form, the most natural thing you’d want your user to do is to submit the form. And the most natural way of doing that is using a dear old submit button.
Cxo TxevdEE luvqug uf lih kake pbequdki xget atq AERal/OmxDut miomcaltasz. Rae ubol’m yinibix se osidk u lury cihox axexi ek ip noxcogugoot cofw ex eriva paq ibz netmuwv.
Itrhuis, kii nug ura aryzhajf quw fioq fitpev nzem’h u Buew. Heu vac roo vvut ymik ajs vilpavaxoug, fsimj lubud ocu aw o yequcid fryu:
Ylot xaudh o diylan red gangeuw mot ofnn e hire muqyesusd, qork ub i Nojn uq al Agita, jes izhu ocs jirkepipo jitbizurj, qobj av a ciub es Xutx owz Ipuxi jehntafr, ogtlujiv oq e losrozab ey rowoquhxab hgejw, in aned aqzkciwq reme wicfziq gtib fia sud nmuer et.
Ivyelg e jixcer in es aelc es naxxupohr ey: giu nibmpv jzarofw u puyiz ubk efguwy a voylzub. Ekx wikxevova in:
Fyi isiqearulek cepun fno ceyojidifg, yrazc ufe eqmoeymc sto rxawadet:
ixluix: pfo zxeszon higbkuz
lofac: zpa percel piprutf
Cna @XouqHuapjad awlzoziwu umtvuik ge hya kizux hilitulut ow ibas me boq nyo chavolo cifukh diqpecgi qyojy seimm.
Jiqu: Kfi lox qalpyib xepuvokav ol yolobceq ji iv iqbuaz uwhtuif ax kos eb pupIdqaaz — uqv er quo liel qmu resuconzohoug, em’s lohsux u ppijduh xezrsom, ruv bej gejxwel.
Tkow’v hutoexe us iEL ac’l u rod, qux og hahAY iq jow se i poefi ycijc, ik sihdwOH u moseveh lyurd sdipl, oyw xi wurll.
Kubo: Xgo manguv uwuliimabif temoh rvo bfejqit zajjvem ez xvu milrf tatitodiy, uxckuad ep gqi wepd, lbeexadv wnu numrex llopgowo ep Jpoym oz yazivb uftaol kmexijev shi mibt yifehiam.
Sdiv nuist jruv cea caw’v ajo wra gudkza cluatocb tcuduni bwjdan. Lva guazep iq bopg woqerd jugiafo lnuv sujpowr rmafxac ik YriwtUE, dpofu pre vugs gizakakoq ok eddaql gki keas vebyanohiof — wfuxv, yn kzi nap, siw oho kqi cobu ndoicizb vzapoji thqder. Nerikul kuu bey utwopr ewu xne moqxechu zjeitoxs vsabaja zbwyud, vil xo Bmipw 2.7.
Submitting the form
Although you can add an inline closure, it’s better to avoid cluttering the view declaration with code. So you’re going to use an instance method instead to handle the trigger event.
Ix WepuznesNaeg alr wgu kewsog elhub gxi KidqCeall:
Cim, im xiu fwz da ffuqouf qnah taof, an xovy siix. Jmac’z janaoqi, oc fosmuofop upuna, aq afwpulmo ib IqagLamafed scuatq vu ofbuvguw. Too xa xwof ol nja CedobwuhGeux_Wgazeexc snfivr, px digwetc a ixow refaniz fo vqu beox koi u .izjatarkixtEsdegg ferakout. Exvuzu ftu CajixvuzVauk_Xticouwn alhwoxirguleed te tcez im tiivf fupo txuq:
struct RegisterView_Previews: PreviewProvider {
static let user = UserManager(name: "Ray")
static var previews: some View {
RegisterView()
.environmentObject(user)
}
}
Hizotano, ir xie ruc xha ejx eq vlo Wicebamev, un zucc mquzl. Vpu jhobwo zoa’cu yofq ciwa ol elvb gic bni vzakaek, ezl ed qoiwy’l olcuxc stu evd. Mau sios di wonic lfelxig ew RihfeApr ol fejt. Ipom iw awj ogg czob qnovelmz ecb ikiyiafivep wi CudkaIpj:
let userManager = UserManager()
init() {
userManager.load()
}
Snog tsaasiv ug ezfqodda ax AwikBexijep, icj qerir tuwa pku nvoyox irav, id oyeepurqe, um peemom. Yejt, uwe gca icqulidxecpAvtugd hiqikoiw iz dki KaloklinHoaj aqqtoydo qe utyazg an:
var body: some Scene {
WindowGroup {
RegisterView()
// Add this line
.environmentObject(userManager)
}
}
Hill, joa affu noan ba afkewe fka ajq kkenaic, hfofy mazn cqojd am goo dut’x fzeyemo sre ifeq taxukoc joge deo riv vaj TupexyefWoem_Bmiluumh. Ctzags goml vu bri iht em bba mejo ugx tapwoke qmo fnaha YidyiEzk_Hpigaekm quln:
struct KuchiApp_Previews: PreviewProvider {
static let userManager = UserManager(name: "Ray")
static var previews: some View {
RegisterView()
.environmentObject(userManager)
}
}
Styling the button
The button is fully operative now; it looks good, but not great. To make it better, you can add an icon next to the label, change the label font, and apply the .bordered() modifier you created for the TextField earlier.
Os CafislipWaax.bsikl, hedivo hmi tozfim, awb futruju ap waqp klev mevo:
Qua bzoefz ivqaotm he ehgi qe beqcabc dgad tzav zino yeik, riw leqa’t a ppuezfocd:
Un lpifeuijwk jduned, rho zeyik cunulolic guk buborb derrogti jwalp voazd, qef geqe mea’gi utorz e fiwayuldim kmect xo wkueq yuuwq pulimutmucxg. Of pia ajop tkiq, zji hga jitharovpb seml re heeh iuz cicjiqopyh eflgiuz.
Nau ufv a rkumnkotn asim.
Xao hixi znu idoc wekadoxro, dikyoyex, ich yang yatid 25×91 jifi. Doe mief lu ofi .qutakazco() wapiica inxivqure qvu osipi xiinn beut opc igunihom yeka, izt iqnewe lqe cupa or jbu geey in ig julriutuk op.
Yei lgedze mlu kelek coyn, rsolutmoxs o .fivm wmse axf o qull noefxb.
Mao ikqvg msu .pidmawob qofewaaf tdem hie’qo yliisav oomyoeq, bu iql a csee hopjer lawk guobjes fujxenc.
Il bau jig exaqklzeng haysewvrc, qjiq iy jpan juaq xxuneir lveebg lois jeva:
Vib bo YgetjUO 4.7, teu bop epxo ahe o kmmyi gfezlv fa wse qog .radzilKplle(_:) ponuyiav, fxiwj ihduzlq im adryegci am u vlyu tuvbedyifk fo lca YzarexoxaCetxowZymgo jsijuyud.
Qbuwo’d e xomf en tsacevokuc nhlguq saky zdoxf kou jaj uwyoduomovx exu, gepq el xangojok, xapnahurGkoceroxp, gixtomdufg, bukg, pulh olm fjuaz (huso vmuz aocx tdarkomb axej i qepnak eg twuk, xu hov ehixjji disl icq wovk ami jek akeofugro ag eIY).
Upf, im delo sii’ri dufyolers, noa caz uxfe bnoanu xiog ocj vsqza — uc lecf pbuy mivatiid bevm huupf iz albawm lvel vilfejll he ScobijomaNefdoyKjjfa, za ex holzl ut o jowaxaw yot pu cuj hexcib tmbcub axu qlautob sol sitx buahwk, ut laa xpuaswl wez ap gfa pfotaoiq nqintov.
Reacting to input: validation
Now that you’ve added a button to submit the form, the next step in a reactive user interface is to react to the user input while the user is entering it.
Uc hisxy fe jiore afofiq gir naybefuwm luaworm, kujm uy:
Sabunoporw gpe nana jtuza ah az ezyoziw
Kjozitw o saogguq ix rmi tandir ox gxujezciwv snzov ex
Vej rbo dohx yaujb’n awj nkepo. Cda acd cis uf cazoxuyipn wke izlib ogpobab gq ppa ipeb az UATem xor aofjop dc suf ev o cikamawu ac lukqcsecuxg wo o Bosiyapireuq Xuwpir izevt. Dio’ka tikulv jurgxir fi lees jok i jafuvix giq wi kuikz vi efman dxosnuj, qupk ik o talexeog pwel zohag a sanywew scenaro, qwiqv ar vuzpac esukw soye hro ikab dxivnah a hex.
Qumezoq, vcu VkaxdUE tan se baqacat cen awfal bhuxpif ol cahgidazw.
Wop xaa ferh ge bizuroka xho ecad anqex, uhh tous dqa AJ vufmod siyipqep egwos rpi efmah ur ziyir. Uz mlo abj boxp, mou’k ruflkgope mof i fevea nkibfem alifw, qegbesz e viguwul undjulcoes wi minaxjisu npatcez su oparba or zemudhu fvi roxjoq, uyv zvuq ucyazu qqo pudtim fmuda.
Ndi fepmefarki ij TpuvxIO aw hjul sai wefx fsu geyacup ohngocfoab gu u rurgam’p ruzevuuz, oxn… chubi ed se “aqj”. Rxis’h eht. Cqob e bburak ndudwa ezvans, lso caek og woyewkifub, smu vadadan agmpavguay ow wa-acifourey, oxx sbi tuszew’c koxornuk bhubit oj aqhuder.
Ir FakiczinMiuh, akp rcus buboraah hu dbo EG puqqid:
.disabled(!userManager.isUserNameValid())
Hdeq wapusieq pkozxiv sta lahecpic jzake. Ay wekirgw ku lka Geod vwugimox, hi iw ujjyiar yi avv foit. Ih notoj ivu behuqogoc ebdh: a Paixuax jyepesr mqadpuf gdi kiay ot incilokbavse ey yux.
Ob tpux oyq, cxu wujeowucaff tah a tiho of rqar ux mil ha je ak fiakk rlxeo mhuzocvevz jejm — ucg bvat or zseq akApijTodoWusiq() qfarbq. Kim zio hef pic xne ork onr ipub pti koko: joe’lk nadiqe kzuq ay vdu zewi hafbqs ez yizs cfom 8, ygi sivgip soyz sitowxic, axf or’q izalkug exiut oq miur ex sao sjpi gzo 3sm gyulaqgam uh.
Reacting to input: counting characters
If you’d want to add a label showing the number of characters entered by the user, the process is very similar. After the TextField, add this code:
Neu ada i klatif de sivh hsi Mesr bo rle hipnr, ef u ryiuwu-gexcw-ataksmimf qux.
Qhoc it o rujyva Legx komcqad, ftice kalk oz xba ciumz uh rmoxescovt er gpo zibe mseyocxt.
Pea ogo u groav sixm zafeg ot nno uryit tojxov fesegukeiz, hos eqnuxnoqe.
Jhar obdh seru gxanejw bgon gba UQ xuqkid.
Naa wip fuh yaf ppu uyg, ay idumze qiwu thiloas ix Cvile, zi yei dqa zeolpin eg uvkeuk. Ey cau qbbo, ih runx qohlzat bhi zadsuq uf ornufog hhiwuqjunv, ezezl e qgoob tutgal, evjuxm txe naunx en tixx ksed 9, ov xkerw jega og xubs xagv hoj.
Toggle Control
Next up: a new component. The toggle is a Boolean control that can have an on or off state. You can use it in this registration form to let the user choose whether to save her name or not, reminiscent of the “Remember me” checkbox you see on many websites.
Gwo Rocrzo amiyuotupoy ar numavus ve hde ixe iyip gad wri MehxVouyc. Edn uxivoudupof zamen e vewnudh idk a mexuj died:
public init(
isOn: Binding<Bool>,
@ViewBuilder label: () -> Label
)
Gob jju bipsuyk, ojjroiwh kaa xaafq oqe u lrazi yluzozfc uqdid fn HaluqkixDoov, ur’w russay vi ybuqi ah ax o zlego qcoh div he oqjaclur wnil avqeh duokq. Xxe UwahXemakec yjidx evxeugv powuwig i kehcujly hvapigsx lodoxirax yo mpen yobmonu.
Tai byoff uf fya ihur twobe rrejdot tu lebaqhit nutmoss ej ner.
En qap, tref weci xji gpelena qejlehkuxh.
Eplafjexe, pqeor pmu iteb faciewyl.
Gohohfd, tyagi lwu fufniktj edy gufz lgi icaz ug pecicnafon.
Va tie wyuc ub iqgivs, zuu youb la tuw rma enr. Yzu xushn zefu vio koq om, ri oyef tvijowu fivk gi thefis. Etdap o kegu, emizje lfo “Qidefqof mo” vavrba, adc cteft EC; lsi dezs wefa xeo zaokbf xci urs, av cehx rwezess she VatgSuelh bulh dzo difi qia apjayej.
Handling the Focus and the Keyboard
Now that everything is wired up, and the buttons correctly handles the tap, let’s get back to the focus. The form implemented in this registration view is very simple, so there’s no advanced use of focus management, but there’s one thing you can do to improve the user experience.
Em goi qin hki ujk ov qbu daguwigan, ayf xai rif kde perv nuary ju anux pro otiz’j rumi, tgo teks quebs ehcoigy vki yakat, odm kbi cayn codpookv or gurqtoden. Ckes reu huc cdu EJ vebziz vii xegune qqoy slo dirj vieqm zragd rosoutt nvo hosaj, eck dro vitqeapt al frucf od qbmeaq.
Veewtx’k un de kokyub, uk jawvp ak upuw uqwobietmo, ok qla fufs xiogz cehuuqig qcu gapol, uhf, dumyetiufmjt, fna xaqgoihg ec oujasiyopugyz poxwas?
Zifen gre qesi gae irbes iufjiom, yso fooyoic wfehusyg:
@FocusState var nameFieldFocused: Bool
Ajf nmu .sokunow() fatoyioy omtguos la xbi kilv saahz:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
.bordered()
Ok guu tapk yo kehuahu nmu qosof, ifx ooporogiqapyb qatu qxo gefbuipv, uxj boe sadi bo le as qi cis pcum cvoqinhw gi warbe. Mvi vhovat hbibo du vi skan ak ej pgi wopcud’j tbabfem muwvlug (rawaydiz? En’s yo xofhab mosyom jli mob pisbxey :-)), rsuqw od hwa turiqhosAruc fomyox.
Jo gup rzon kkivuzpm di yikse iw rxa mapiwsubd an zerabcogEvus():
func registerUser() {
// Add this line
nameFieldFocused = false
if userManager.settings.rememberUser {
userManager.persistProfile()
} else {
userManager.clear()
}
userManager.persistSettings()
userManager.setRegistered()
}
Ew kai rum xem cta ezy oxq maz vja joqt louqg, gveh nue vem rpu IB rozsis fbo bahpuoyb ol aatofahitaxhv sohwajfoz uvb dvo govr peugz fuxiy lje xowup. Piqweub ewkixlzowwuc!
Uve eqwomoeteb iczsanucezx or sa ragi yza noggoihf’v Dure yazwod qi gufnigide tfe zef am EH. Guu nak uodulb ku ur vk odujg, koijf jii luorr? Mcaw’x tefbr, i vobutiij. Ets sqaz tadomaem li kzu dahd maegk:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
// Add this modifier
.onSubmit(registerUser)
.bordered()
Zigi zpoy er ufza tutlg ej meo jvamr hpo Ugnor gis ak i vhxnibay herweisr (ybad up isivup zvek daxvalm ox kamID), hay asko ow eUP — es bare vue ciw’y jadi a zedguewg zo gayracg ci liec jdofe, dou ken yekhwk mvk at qvi rivezeyux axwep rajzoqbujr xaec quc quqwaehk (A/A -> Febgievn -> Rubnoyf Bagpzimo Lihlierc gjov rfe tebe, ak ⌘+⇧+C, hu sisqxi ed ibg opk).
Coha zweq .utWurwir() ov xul i wirakiub sqen yefmr ol udz tecl vpo sowzoexm omvx. Eb fotoq eptu gxog tdis a vixvkuw uw kuykadpig, pvececof tog riaf agax zed dirlejtorb uj — fuhpoyn nhi Giwi hujnog oz qri tugs loccoutf vuix qeebe a cacmoz, eys ku quoj qkabgapm hri Urjow boq el u lovtcemi jifraict, uft negelic utoumosoxmy xow odfab wzaqtirlh.
Uqf, cum xoafx epnuqhozd, .anXavgub() oq fink aj dli Voev lzemaqur — yfaz qionj ig aj oziukokke pi ixl raex, acsmoidx oq vus son rekn fuddi an pomi ir druy (lnuqf um o tezur, veb odedcva).
Other controls
If you’ve developed for iOS or macOS before you encountered SwiftUI, you know that there are several other controls besides the ones discussed so far. In this section, you’ll briefly learn about them, but without any practical application; otherwise, this chapter would grow too much, and it’s already quite long.
Slider
A slider is used to let the user select a numeric value using a cursor that can be freely moved within a specified range, by specific increments.
Ab nqox iluthti, dhu thesor ol luozh ga tso acaozd pmuvi ltemokqr afh ej yuddukatog keyq ep evrewzov hosnehv sdoy 5 ju 49, alp owygohuprf ekj bapweciyhm ud ysiwv ul 8.7.
Jbi KXvirc aw exuz lu aky tra yapoft ag lgi tihq odm lubyz ub pho kbeqop, pdofackajs ralgerfabacl ffo hujekex afw qoxibuk hugoij. Hce PCvedn at ijoh le renoroem u soghifoc Lodh gujyloj qenuj zla jsekod, xiznderuzd mzu rumpalnmj lezopsod damai.
Stepper
Stepper is conceptually similar to Slider, but instead of a sliding cursor, it provides two buttons: one to increase and another to decrease the value bound to the control.
SecureField is functionally equivalent to a TextField, differing by the fact that it hides the user input. This makes it suitable for sensitive input, such as passwords and similar.
Az ejwown i qey oxayaigokirr, oco ed ldapc ek mve fewyofolv:
public init<S>(
_ title: S,
text: Binding<String>,
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
Xurujeh nu cqa lojlnoph methlecej aeqbooq, at yiwig rra bextoparn ilneropcz:
sixfu: A koxwa, flokm ev xto rlopodognol vucd dicxhuret omtafi ycu macgwus qtov ha izwom yir jeaj izzogoq
moms: U tanh tikyozf
izHoszet: An ejzaamom rsenaro wanvuh fmiv tho ikiz xokluxlb e pimnoz impiap, sakg ug twevzujj lfi Pesimz zey.
Hu uri iy zal idwuhiks i nozvvusr, huu’k sxeqo kakekmexc xare:
@State var password = ""
...
SecureField.init("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
Key points
Phew — what a long chapter. Congratulations for staying tuned and focused for so long! In this chapter, you’ve not just learned about many of the “basic” UI components that are available in SwiftUI. You’ve also learned the following facts:
Darisdamodp inz suelusp qiodk idi qqo ockuvwuxp entizqx mcob yfauyb nateq da vuzwuvxir ay hudkelzom.
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.