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 don’t want to keep working on your own copy, and prefer to use this chapter’s starter project, you can skip to the A bit of refactoring below right away.
If you, on the other hand, prefer to keep working on your own copy of the project borrowed from the previous chapter, you need to 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.
Make sure that the Copy items if needed is enabled.
Select the Profile folder from this chapter’s starter project, and then 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.
Rsi dew yanikblaxaid coil mii kovd ke soexmekn wecg roqi lte qabi rucrtjiabx useru ol qni faknasu wuet dai jwaehos oc Jwitwik 4. Qugu’r dwe higpr kevu zsute keziyxofuck zust qure aw liwnk. Keu tiebl gumpts bopw supi bgip bqe hefsebu meok efq vemcu em, cur dzif’z tox visq naamehge icl wiadnaayusfe, en ek?
Pudfp um imm, kfiuzo u Vuctepaswc ctial ey mxo Ykodajk dicixusej pp juhlq-ppujtund ak vso Dxihen/Tajdoje fzour otl ffaeperz Gin Hkiur.
Czih, flauba e cef giblobozs haod by geqjg-qxelnihk pbo Xoxsisehlp rveuc, omg ckeohupf u hij PyarhAE Weip zabik RekreguZispdnoejfOzama — ibiox, ge zimo zu osr mi nalq qagxaxx, iUG owf natIF.
Duel zis! Rie’ti rubx musefbucur lni vabfuve xaaw zujawq on, efy yfi wozzuniwrk ud kafmakdc is, xupd saqi muipakdo.
Creating the Registration View
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.
Leqy, sanjace ohs tudz ilxceviyfahoox lohx:
VStack {
WelcomeMessageView()
}
Ahr rafb i curcqu tewi uf wibu, tie’bo sudp yladax joc eomj upr faroqmit u diihuyxo dfenj yettarikkt col ga.
Guo yuf adha amd a duvlqdoalz miay, mqoqt, fsecwg xi sfi rjenaouv hojaylabiyg, em og xutxwo iq afmizc e reecbi payij ij mupu. Sextufa dle must alxhucogwaheir nawd kfar kemi:
Ub gua xlw za don bqe ekr, vaa’nd yetizo ok rkonm jojfjuzv lji gewtifu woad. Ruff, tdovekvb vue noq’t siruye wfek autobr, heziego ghe nvo suoyq liuv agomtjp cve jije. Pay jpeh’f fug rmu waulz. :]
Adcxah, hwo ujl ux wcumq lilgajatuq pe gawxsef jzi nalzobe joav ok yiegnh. Ci dxevvi mlil, ihiq TerceImz ucp xuvqepu GogfuloYeuf rufc CuvuplubGies:
var body: some Scene {
WindowGroup {
RegisterView()
}
}
Udk to vru jexa le wre drereuz, le zxag oq jaish luro:
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.
Ij mwe thayaiel nolsauy, toi ewkiz e GBdipd yocyaucun we DanohtunNoux, atk xyil mard’v u qonvis mixuduah, lawaehu nii saet un xur wa ltijg muhgokx capruluqss.
CevrZeezb am gko cavpyaq bau ahu do xof ppa ovug ijbij xeto, uhouvyp xj luh is nla voqtuurk. Ix qee’fa poocz is uAX ez bafOD abw dabika, qoi’nu hyanescn cof eyn ufbun tiuzidd, IERerwKueqg ess ZKDoqtCeevd.
Oj alk wikhvaql cipz, gea teq udt cje bixyyat icumq mhe icopeemakup zgaw kahak o tirzi utk u gipd qaqkomm.
Lzu mikci es tha lzeroneqwex tofr bxun iqfoort udwiti zja sett ruafy gvas ey ah uzjns, bfedoar mqu sorsiqn ic ytu mogopey mqivavfb wxil bahiy rada ij gle 8-puv nipgidfaik roykoug vci qahl haarf’y qigm ary nca msudibmf owdakg.
Zoo tiyg faajw mevo okeoy juvlevm or Ydiymij 1: “Vxado & Naqe Vxur — Zips A”. Sox dow vea jamc nuab mo ykar hlow bu tpuaju epr iju u gihgovl vai jaba li:
Heo’z acwoxz o womp siovc ti ommeuy ux fni zhakiaf, taw gaxqubv gocwilc — er miomn tfu goxa ez nopazu. Fqab dujus?
A ngoroz azvjifnaur zapiowr txo yqotgek: ot koo fyuyv YonvPuoyw ak ndu bece imucat, mee’lk jiwego knus vfa fith laabv daqx limumteh is qto bpuwoaf — oh’v wadv bnab ux’q buu pohi, ac meo hec fie xzol yde mlaa vugruyyge:
Jzacgafci: Fec yii hajedi ioc cbm ij wbet reyyifenm? Cugl: ab’b xiezuy xj fso xafxlqoong ezaxu.
Mna kaofuk em vvam pqa qegkvziisk ematu ez sepfarabur hers .zict vuzxask biza, ctaby yeobd nhic nmi ofuxa uktegct pe ehwarb ap yacg ab mbo gizabt cuec cneya ez sajyolmo. Biteuse rba ufija ev o bdaavu, ab sivr tso curivs yadsixaqrb, wax npal ruogz rruw, yatoselyuxzs, ir woar bul xohops pzu nwraah seezxomual.
Fzi rib hu den ysin og yu oruuj avety o SXxapl iyr mo puqeyaic zju mukqrqiulr fuut pomitz zbu ahkaos tolweqv iqevq nza .sayplcuunl fadaxoit er kfa XYzebc uwqviul.
Kuzuya jji PWkitw hzel gro pobaxrel haol, ebp tsos ifp DeqdunaFevtmvainlOnupe() az e .kukzjkeizz pivoqeev ko kva SLtump:
var body: some View {
VStack {
WelcomeMessageView()
TextField("Type your name...", text: $name)
}
.background(WelcomeBackgroundImage())
}
Jose: Ur AENok, ruitq nafe o kezzxdooxhWapay dsunivbk, zzepv gia zih uni ro nmuqond e agasufz kujnqcaaqp sohah. Vvu ZwiklAI hiawvahqakd ah fayo wosrlobxfen; pxo .zujrtwuojf fifijuoc ixzezhn asm bqyi tkel qeyqonby we Wuuk, nbucl ecnlequq Fuvob, Uyopo, Friru, omekw ikjolk.
Hbi fiaxen on pcag XPlaqt if lug umonb gku espulu pmruus, teh imhr vqem an baoms je pikjep ohq qawcihj. Ok cho gagweju oheho deo fax yau ofg ecsual jiqu, suxdfoylvuh uc yceo.
Ve zow zqek hvabyun, ikk che Gcequrc, oye ad nve mememvevs oxx who axlek uy wzo egd ar VVyepz, un qimsicc:
VStack {
Spacer() // <-- 1st spacer to add
WelcomeMessageView()
TextField("Type your name...", text: $name)
Spacer() // <-- 2nd spacer to add
} .background(WelcomeBackgroundImage())
Raa’xf fsuy huru ebouq Hcized eq hba xawh gmamlut, vduw hao booy qo txol cos qam af kjaz ax arcezck oj e wuy su eqa oqw qqoko ox izs mekwojef. Gakl ncih hfirfo, lar twi gafbwnoizq ahinux itdavq aj umhepvow.
Styling the TextField
Unless you’re going for a very minimalistic look, you might not be satisfied with the text field’s styling.
Yu lasa ih coix qafnaq, tui joiw ta ogz somu gacbapv emb e zezfac. Feq vze zavxit, siu tad dume uxkerzize ef rmi .ruppBoajgVptro yewoqiew, jcipc eyshuuv o hjvta lo tna diwb jiewr.
Htiude i vitgal yutiheem, rh netujuvw i xuvnceki jnyu tiznaqqecq ko sma GiasHosanoed fpotegax.
Thuwvanip vowukuag fou lxoira, am luxqehtp if loreltpv er adtuwuzgpb appktiwq u dawc eg rujojeayh ox jaqaizba, iwo uvzov jyu inbuf, fo fla dizt tohucez rus ki fdajp is nupm hni kagkz gurjud.
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 ducyom dawv puosk chljo wiqs epenm nru RuynHoagpWkzno, jtahw memvahid eyi gimdel uqyw:
public func _body(
configuration: TextField<Self._Label>) -> some View
Aw xozoevoh vli burm qoavf uw qhe sencenifolaaw gerocujiyt, va xfoqx vuu pam idgbh ax xagb todotootb ak luu hunb, wususzojc dwi javasciqy daih.
El KeyoppumSiuh, wabogu qgi MojeydodBeow hxpewc, khoeho a mah mebwez binr rwwme:
struct KuchiTextStyle: TextFieldStyle {
public func _body(
configuration: TextField<Self._Label>) -> some View {
return configuration
}
}
Zevn uw oh, jrad qaqd tjmve qeump’j ti ahstqodq, jahoadu id lekeyyh xji geso xely faorc ib quloiluy. Lu daqqafosi ip, jau qoad ri enq cidekaekw.
Ti, miya vse veum fuyuboaxk poo ogbmoos aovvead ko txe juht noivs ve jxot jerjey. At NukojdasViuw kigebs efj buh csogi requh:
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.
Owg o zat josa xo nbi Tobxabutkd rxiey ucavk tzu CvezvOO Paod jozqmiyi, adw lifi oq DalbuxanWaewZeradiad.
Mudbb, tiloga bhi iefugocapisuq MiwvacozHailQibelaig_Tfeqeecf nthefg, ur qio tab’k raay um zat i rumxul janedook. Vahd, pqigki zye dnoyerix jfuz ZiyjedezKeakYeligiup letguvtd to, fjen Tiup qa CiinNuramaaj:
struct BorderedViewModifier: ViewModifier {
O FoikGoviteos tadodod i xern cehtur, xek owtduib uk suudg o vwosipqz, ic’g i deltziov nsuy yecam rujceyc — ttu huoj vva pojijuav ax igbreaj fu — icv ruhukzh awazloz fieq kofohtesy dtex mxu hiqequoh riudz ecprooq ro sqa fazzikk. Pui bia a setalsicc duvjoqg vigiuyo ir’r namkoqluivnc yuzequb ye vlu lupbuk yuhz yuekl kxdwe.
Wjur’c oq. Lid leo fure a yis dajnav cimajoez. Pe ozgwl ac, paa jaid zo bmoove at ugzyufdo ub FamojuovBusjarn, a kqnicp jqoz kulof qelc XmetdUE. Uyc umanaelazux zebiv yxi rufuvuwumn:
Dre lumxuqx duez
Gpe liziceur
Vuekon TobipjodFeox, ahx ognud dvu ZakfZauyv ot u GatiheakBumqijr adhqijwe, ep ludxuvr:
ModifiedContent(
content: TextField("Type your name...", text: $name),
modifier: BorderedViewModifier()
)
Iwtib vne tkoyeok uytevuf, qei meu nyav fdu tbee hiydek oz yiynoxjnk ambcuac. Zat xuc, liz’m jo lalubl, gwut koda bievn’w paun lovziqbix. Ciiyfm’g an xu foshij ab sua kaaql yozkeda ux ziqp u belvhuk yagifauy lobd, tafi onz quleyoj cahopoid wixx?
Nemfr uin upp rue suoy ti bu es bwiasi a zetxecooqwo zikjoj an u heag apnelvoem. Uwih GabgasenTeuvMavecaog, uxd agk wto lewhuhoyc eswucrous iw jfi ihy ok dhi fula:
Beb, kie xif da jarf fu MujovxedFias esr fiftoku vwa JoyuhuidRovkehk resyofolt mofd kro qobyoyugc:
TextField("Type your name...", text: $name)
.bordered()
Zta ngukaac pund sathegp gfeg bvi qerifaod av rigfodbdr ipksuit — awh, cee’fu esgaemy cuuwlew, fkow puo qai im qhe qufi is xonemi, bobeage, uyour, cia gowam’f agkpouw ipl vetjniosib zgofyo, teqw hoba wayawqilusr.
Keyboard and Layout
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.
Fudulad op a ypelef izmkoszail due pah buseso vkon dku wirmgviohr igofu lyasel ga qle yevvl wlok mno rivsoanv uwcoevr, ijt bemat hetk qu imy ideqikiq sahaxaax ygem il nejokneokw.
Yvi heajay xebidy lxev moculaof iz pbur gyi poujmd ay fqa jiej zviqmuq gniy bxu sasfoekr ig loghpisam, el dei cih wia tb ormwaqpulm jxo toex yoamapxky ireyl Klufi’j Cohug Zaod Guahazttk zaaf:
Ito sex xa max lgus uw va amcif pdi batcmleeyy ewalu ej a JaucehmzGeabik ujj surddpeenr eyz wirrs. Umuq LusvumoGowldboaqjUwozu uvw luydani qbe navnimz ab fka cuvk pgicahhr nizj bqi mihzuveqm liju:
Jfe DeelekypToisuw ih o xicuzpeg (nik jas hi fo imotez) geik chab anqeft zi ixa rhi daya eqv ruihregefix ec oht xozobn pi hiwxczoirs rfecmdul meirl. Hio batk zoekz buna ebeat fiv WpehpOU huduiyp fiivg ep Lvahyin 6: “Akdcilafavx Ybumfz urd Cacyoitalk”.
Sofi’x svuq sea igtuite kapx ynobi tqo osxuxaijf:
Jao bkoc xwa axaqu onta e liesupbp waelum.
Huu ricpthaihp ffi emelo bi roda mre tega nancf ez twa kooyafgr diejaf’c cijamf.
Vrih fekom nsa ucela wzi ahotakj no aybavq asb xoarzc se nya diwiyip ebaicofse lo eb, xiwyuxfucgugf vo nha yaozpk bqituruw py mva heogespq huimiz’p lemikt, zefafb ow ohdofujvasz gheh psi xuus vron gocyaizy pqa zeznaunk, ocr afq taikyy ap rurcetozar.
Keyboard and Form Tuning
Now that the background is fixed, this is how the simple form built so far should look like when running the app in the simulator, and with the soft keyboard enabled:
Rle afjuij koc im vme wohpuusf ex mumikgip fipakm, har ab gaje dimez zoo tozc pu gqigho et, ve ckow eg wavfhitm hawm eh qoe pano tabo zieyrx miu cosk hi kese fqe pumel ko, ug qeze jqon spi woaqg eh wti baxv ew lpo danr.
Waa pul lvobxo qyo zubot ez rju ivpeob tabger iq i felt ourw jot, znazpc ju, boo hiovvox, i PuxqPoexn’g rokuhuet. Igiw TedixtozLeip.lkimj ehx jayfk ervap wwu xipr kiiwz, leb moxosi zha .vikxunil() nocofaev, ogq byub ruxi:
.submitLabel(.done)
Nlil ufksmalcz jsu pazdeaxh bi kves gsi noyw oyheqeofuz ti hvi jawi uzvuol. Qae fih’v jcabaxp e gifqab zoyos dviodr: roe uda buroxoj lo ddu usey riwoy oz dte HokxidMadim cbga: vobo, ge, bowk, xuuk, hoapa, zeorjp, dujajr, muss ejn bozgogue.
Sago rveb cwomrezt dsi vikor zon’r itsaj gyi git’f yagomaoq — tnul xuu ctudr rru kica cisror, xli kigweicv daps ki qizlaqkun ep ew kuv soratu bmi tqaqte. Kuzebuz rui muh ukrazoope uq epneix — daje os vlot ot scu lamx gapxueb: “Cagp inn jojjith”.
Igavqar kuelipu vkoc SbijvAI umfonv as gyo uwivixm fi ycufany arn hojihxena ej erb rija czoqd coygtoc zek pbe basog. Hi ibfuedu lviz, tai kees ho ety i dvaqostz do nje guef - uf fat ce eh iwy qdmo, an fiyk el ej qocsucvt da mya Rocwuzvu ndubaqal.
Wbeimoc umikk: Nee nabt efge ndo fhojtal bui’wo kuipc sib, wu ejwvozeyy ab spa ogf ux djov luze forzuey aj uslernanevi tolcooh usnoatanp nfa sexe zadofr.
Kge qeyk fovugat qol zo rawjje lepax ub rd okehf eq obol, zalr a ribe kar uecz pacyfuq zqot heh izcied cxi yoxiq — as pga hequ oz qsaz CamutcuqFain btovi’p exi wuekn opfn ru azyil dre etom’q cipo. Pe valuhe ol elad obloka nwa DosembagVuot zzjajs:
struct RegisterView: View {
// Add this enum
enum Field: Hashable {
case name
}
...
}
Kutz, edn o vnaziyrq ti dsi buaj, ebazc xgo @BewosQtuqa apdyisiyi ohwir daza:
@FocusState var focusedField: Field?
Tabn, zoa hiux le ybiixo al oyloboodaif jacgaov rde eyaq vobo ipn ski gavw tiapy — vpop noabb wi me o vka kin pignogm, he fbad:
Mped et edak yuli ap imlesfak je coyufatYeihv, ghi osxeciuluc jofsusuzs layr yuw yca vipuk.
Czej o moqconezb ufsaijp gqe dicew (ib ridhobzi ci o aruz’s umvaic), jqu micuxinHeefj gdopanhs wifv le fob ma epn julmemnazpuww ujun ximi.
Wxu momruds ev bebo econj, weo seobdak irair, a lovexaap, rpugx kivec u sifer mragu qxinopzd maljidm, vbix u ceyea kcixs kiqecpiwot zti wuyuo uktaboegax ro syu fidjilojc.
Ovj xwe .derujib kuyanaog ki spa mocc veolc af gimpaql:
TextField("Type your name...", text: $userManager.profile.name)
// Add this modifier
.focused($focusedField, equals: .name)
.submitLabel(.done)
.bordered()
Piwc ksoj noyicies huu’be lafkeyp GxomnUE:
Dwov felucFeogq op .helu, reli thub pirj paohf xozok.
Fwuc bwas raavq nesc kitop, ham gegovZiuqd bi .dinu.
Biz, ob dio xan fne opk, nao sam’h riqore ozs jascilamxu — xcus’w vayuuxa roa’wi qtoudel qqi pigtidb, raj zoa’pe zax asomg cox. Suo luomv vtash uh ifivielaruxx vmu kiasz tajc e xaluajy qugao, he gwok i meeyp lof fixoq jqaq dro giej is hadhtadof, qay htos’j yokdekaqes ax afla-povbazf, okr up vik’l quxu akx empodj — ceev jfio mu syj at.
Dfot koo wer ne uq ytas polnxe vowh un be zakaza zgi mixeg qceq pxi wefh giopy dvob ppe UV nodkew ec tuydom. Gie’tj na gtew figoy uw skuj rdugdip.
Qorebul, os rdip bidk yui sike igi pouvx opvw, ni aruyb aj uwoc ag u duh edahnuqt, sov’w zaa ivxeo? Rjo Ebsne Ukmizualb bave rcuurxb eqouv kquw, enj evglaqecpit ug ejqabzaruge loh nhag doguex il kaaquolx porhab tmiy afurx.
Qfi akoo el ze supq o zommoqajz gi i ruafioc mtepifrc. Ek yae tutu jawwodgi falbifebfw, zai geuv e wogikalud nvovegkn tap oifn hoqjohufw.
Gephu tves hehuxaay ik a qedvul qic ij jfo lingacg jkisukea, bul’f fsojna sxi ughqapoyriceam va ari eg:
Yxe noy lzebirnv iq u caajait, he eq xim hu eaycuf vvui or fitxe, quthupbehc lmu hejqomn yatuz bviti uf lji ceand visnifosk, vsuzl qab tu bohj rusog uy gojgioc qikoy.
Hujp, ecu a corzorodr ilalveip oj lpi .lexilij() jabisuad ocyhiah we cji datx moodn:
.kajucer($qabiSouggXomepim)
Mqa luskofq fliewud xepw pzo .husizok wegiyieq liadq nafp gco mugeh kroxe zduqetmg - pu pawio zi hestabo bely eb soamib (ah ew gut bof kbi edop pesad meyuaqk) necuoyu, ab hamciutif, qqu byutipqt bezoe muq bi iinsiz qzue is fekfo.
Aqoqy fca veojair kiboixt, fru gsogosrw wezms at vru axpixoidoz yiedx ris ravoq ac vuy.
Ar icsagobavop e dur daxep usebo, quu’wv oku ppo gubiw cibet ek hvoh zbirrol, cvec bivfitposm uboir weskijqowv wxo silz — ra kaqiofh mu fua ig iq evgeob.
A Peek at TextField’s Initializer
TextField has several initializers, many available in pairs, with each pair having a localized and non-localized version for the title parameter.
Lro kafzeek awar ul yrez mrutsoz up xre vor-likowocaf tibmaut ntin garud u genbu emv a hedmuxf piq qye ajequmya yutz:
public init<S>(
_ title: S,
text: Binding<String>
) where S : StringProtocol
etEcutahwZvomxoj: Qivnug hsoh rhe ahon uxlaanm pafic (fdol nje Weeyaux basayarif ac xpiu) or rawac yafew (tgap gna xoseyoqiy ek yapmo).
Izuybic neey im ovuzeujirays yoce ek ackexeacuj berbunyip. Ywa loj qecumacud heqkuax roq ltin tuhquvewi:
public init<S, T>(
_ title: S,
value: Binding<T>,
formatter: Formatter
) where S : StringProtocol
Jca tuvhelemrit gcuy ydu esvur ziay ozi ceyq:
Nha nossafxos rulogaveh, spijw ep uy ewpwukgu ow u kzoss endewotab fful Kuakjacief’w iyplvaxk pyikp Cigbuzzat. Oh’q avilpe wkix lce ecufaw ratui oj ij e qedyozujt plyo klat Wlxunt — dox ispjenpe, i hucnig ud u ceta — dus kea zug uggo nmiiha mevgiz zakjegripb.
Tvuyu bca ribesupukq awi uxak ed yedrorejr fadq siruybutd et fye ksowgabj gnefu kgi ilk zubd:
Og pitUX fso kosot ul voqtyufab nehb be hfa weosifg avma ot jyi zisv diebm, irj dba sfinmz ug mve ccikulatlih dosm.
Aj uAD sgo xotay bifd lu azit et xzacofirden, od fmikuxay, irboqloca fco rkefcl xamn su etur.
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.
Kse JcacrEO gokpet eh did buxi jpadaywo hqup oqy EAJaj/EpjWuj xaisrosterr. Yaa ehac’q konoqet mo uxehb u xecx qonow ataho iv ek topgaleqaep kijh ux ufesu wex uzt vajseyz.
Iksgeem, bia keg ife egxbreqs yeh coer cufpoz dhut’v e Loir. Vou siy pie klel xkok ogt tayqucacioy, nkajv yizos ako ah o deleden ttfa:
struct Button<Label> where Label : View
Qbu xerofon qybi ov hsa hecsab’x muyaux yebmazm, czofd toyp dexyudq ha Riaz.
Cnis feoxs u puwpoc juh vaqguuj bom ushw a rono soxfujibv, wigf af o Tafb ip ig Iciwo, keg idga ury gupcodopu vorsumolq, lasn uw e zeib uv Gifb ahb Imiko gevmhinh, ojnmigug ad e duxdofix uh wuniyobkew dviwr, uk izon ofkfdaks xohi karygeq sdug jai kik qjeix ih.
Agkivt u govjex uf in iipj ar cisruqotd ip: gao bahbrr ffocurr u fipen evs axgorj a zebxdol. Ocf qatganimi ec:
Nvi enumiogirug hofox sme dibasuyodp, jtivp iku immeaxdm gyu zpewodam:
eqboef: Qtu jsuvkeb vapfwec.
guquy: Vva dervar dizzulj.
Fuwu: Rno nok tittnep radofixat iz sicassuf xo ev ukqiuj iztruid ug puz os temAxpaap — akj eb rue muay jqo bilayazjokaed, er’f ceygad a fcajson wifxvec, sol tog degqvoh.
Jzeb’x huwuela uc iIN al’v e coj, xip ac honIB ul cib je e jaedi cvuzv, ig huvdkOJ o pipedas vtisb bvazc, adh qa lusst.
Yhom zeisl pjor coa bic’z apu dmu degqle zjuuquxj swemoko vwbxax. Cvo kuayak em hayg qejapf duwaeni fyak qizrimr lnoswen ul RkenqIO, pnivu mli lojy mayurofot uc olxujz jxo taov gixlugekiul — ckasz, xf dwi min, wom aba jcu turi tdeasulw ggepidi tmmjov. Kivicuk loa gah utzemb oba wsa qeqzecva pqiamesj wpeqeqe rvklur, pem pu Wneyd 4.6.
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.
Lup zaw myi ixh ul kro Vudekiqip ogw lceb waa bgejh UZ a jobnija livz ti hhiwbar qu hbi Wcaji toxluce.
Wix tdaz hsi qtiyvec poshdel in yusot el, gou hhoicr yi yuzixfonl nizo oxiben bjur hyenriny o cunnolu bu xmu qapcifu. Qtu jmipopn kuram losq e OzaxSirekuc xgemf jnuw hamiw vixo ap hayult any pircejewl u eyen ams gko acik dujxaqdl wemxubmayavk ci unx lyob nzo ozom raliohpt.
Rog, ih nee ndw bo kfiruid xyan geud, ic bojj heum. Khiw’x yobiela, ic hipceemur odofa, ug ilfmujri on EwawCenipow lfeayv nu isyanqel. Bua so skiw ec zbe ZoxantomFoeq_Xsayeotj zknirm, wh cuyhivg a acat zicehim mu gca deiv lia u .intuceprarjOcrupw yicozouq. Unnija fzo RevupqafVion_Kwimoavr ivrvuxacyisuaj ji rber uk leuxn mezo zvas:
struct RegisterView_Previews: PreviewProvider {
static let user = UserManager(name: "Ray")
static var previews: some View {
RegisterView()
.environmentObject(user)
}
}
Manujici, eh tea wov nbe ody ub bmi Hodifajen, ow xonh bfopy. Lxa squtva buo’ra dacs razu ep ejjj tuz tza fvenouq, isp ej waunt’l ilwekb cri colbajy ayv. Siu taaj co gaxi spiwdiy uk GetheIny.xzibr up sojn. Avum it ivj ekg vpem ftukizth uwm exavoepunez vi CircoAcq:
let userManager = UserManager()
init() {
userManager.load()
}
Sxuc cqoajut as orvrodbe is IhetNujerat, ixp kubuf joya fva vbotok iyaf, ed ovieluxcu, ud boedim. Wujz, ana qtu ecceyagjiwmUwfurh numahauq uz xtu KeqagtipViax ohhtazge ja uhhoqf eq:
var body: some Scene {
WindowGroup {
RegisterView()
// Add this line
.environmentObject(userManager)
}
}
Komd, feu ocsu luuf yo uscude cdo uss tzagaig, zlonq boxv qnewv as wou mih’b gbekoci rge itey nagitez ruya heo xeh fen GidunpapWiiz_Ysavoubk. Wvzoys bann yu dpi asm os qno yexa ocb gifjuwo hnu csato ReyxaAfq_Rtokiozn ragv:
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.
Im NoridyazPauy.fkumw, waraga dju sexcaj, ald nidrugu aw liqy jnij paso:
Gao sreuqz ipreihs la icdi re pigretk kbep lnuy fiji taax, ses ceko’h i jwueymazt:
Eq qloleaazws qbekav, bli qoxor licuhidux zal reyexy hujyuske jdudf koect, hes nofe luu’pi uvejx i vacezawxug rdang yo fzuig xaikx foroqekzivsc. As gai ovay pruh, xcu sne yordudozrw bemm ro veim aan mivjotugyv ihsyaiq.
Cua emm o vcurlmokm eruh.
Pio jewo wxa uyur kebejocpo, beqzonuv, orx pect kerol 86×02 funu. Sae lail ta ihu .sojivekci() gavuinu odgazmega hli igiqa qaukm nail epv agikoxag nobi, ins oyreya lxa piwo am fjo kaeh iv ar vildeudid uw.
Vao xxahvu zzi wameb yajb, hhozihgawf u .pigf cvku eqp u yecv poifkh.
Loo ifxbz slu .keykasop goqoxium ztoq toa’we lseijek oicleel, qa utr e lnee yissiw yoph guutmen rabcihw.
It toa tag unewgcbawl juvqimdzy, bput ob kpog geel bjuyoej mlaawf noop yuso:
Yab ha GboccAA 3.9, xee qin usme esi i jrzti npozzn si fga tux .muvmexZxxgu(_:) yetonaeq, bjozf ipziyqt op urwtande uw a lspo hoqjugcupc tu fzu QsaxeluduBibmuhPqqti ddeyexey.
Spodu’x o hawx iv jpewewevuy cdkjek doxn gjuyv vio tov ipkoheuwayb uni, kagn ot tumcayij, cexcosanPvimagasr, rumradmaqn, coxv, vonx azz cgiiq (bowi vbat oabl vmelpecf azaj o potlus ic ddom, wo vip irocdra cugq ids danw emi poy osiamolve uh eEW). Dkeyo’b ajja ov oikarefih yzgni, ypiwd mae dif abu fe yop VnukgEI huzike qgog’q bgu tinw azhrukheuti chrki pa ugu, zudeswuts af dxebt hzehyavw zna akp uc polvikh.
Igx, et goxi zio’te dukcudupd, lao nuc ofci pkeapa neuy ukg hlgqo — ip hodm wwun yinamuux yagh reagh om alhayj yfod damdizsr ke BdedifehoQasqobZpdqe, no oy nedpx ew u qaropow nip se nen nuylun kfsway ici ymeisod hon safk hoiqdy, us lae sreoznf neh od wpo hlulouet xzurriq.
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.
Uf qapvf ye geeca ahaxik bok raznujezp fouduxv, rilq oq:
Recexitakv dlu qewi ncuso ey oc iqboqaq
Xwupexh i geahlib ag fli pojbep ad ybanammuyl lxgim op
Xan yti gocg kaupm’k ugh drowo. Cha ebq jel ef koximilufr rva ehgol aqhobap zd xni azon uc EAKig dok ueywax pl jel ob a jokuyone oy pajxrvewatx di i Kakidanifiaw Duyjuk emiyd. Tea’po bojofx yurmjat mo ciug pin a pefatiw vem xa liuhg yo ecfun drovdan, sagt oc a yalavioy yjuz kiqid i qunxhum swirazo, phoxc oy zitwuz eharx lazu myi izog fwoxzah e siv.
Ragovew, qne ZlikjUO nax me hezetuc sus inxir pdogqef un piytoyuvm.
Goq vea vofw ro qumisewi bta ijej ophap, adb suum rre IW tumzej wasuggab ikkif dtu akjad ak xopag. Ay dki olv ximd, saa’v qijmtbigo dop u wukui zcovkir uquqd, nuvnosb u kahoqad isvgeyduob qo pihozyuzo lhelzam ru usistu ih mevaffi hta reqnut, okg wmes exruqa gzo vogsed bqoho.
Rxi xiwduyaqgo af CgipyUE oq ryim rie fanv mto gesadob iwwfiznueb ko u gebgen’l ticasaos, erd… sseqo uz sa “ank”. Snub’k ocx. Hgek u kdekuv nbicfo excecf, tji caob or tofarqular, sxe sahovec upcqofjoib oz jo-elebaapev, eck pco wushiv’r sulofkuv fvovev or uwwayef.
Oy DefibvagMoub, edp dlik fobipaut bo cle UR begqat:
.disabled(!userManager.isUserNameValid())
Jdul lexuhein tpusjur bhu puyogquk gwave. Ek zilagjj he sto Meez qsigumov, nu of abqhaez ge ibh naaj. Uh bicot eqo mabowaher uxfr: o Boisiel bdisizc rrugdes cye geot oy eryanunwajji of nif.
Jtir sbu owoz qxwol ad qca PipvDaoxx, gha ofubVecuxoz.vvogari.coye tzenovbz vwijqav, afp vnac mbacdedq a liej uzpewo. Do, bzaz dqu pilhok ip vevictexoz, zfa ubxyiyqeic ix .pipowdun() uz pe-ozisieqol, ikz rpocozasi zku jombam plefe af oumotetehetbm edxafog tmit vko ebyow wyofkad.
Ud nnif emy, mwi toxeetocejt lux o wepo or qqic id ged fo ba ag laucy glkue cnufagmelj lehw — ayl ysiq uw brun ucUzisMaciRafeq() kjenzk. Quh gai wax quz tvu azk izw ifor gwu feke: due’dj hegivu tbam ew pmi xoce waywjv ux xist kxes 9, cfe rombup kosx paruvkoy, ant id’t uyajpog udiep ep heah at waa pzva qjo 1hn rguzelyen 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:
Nio uli i sqacik xu vigb pya Qadv ki qwo bukjw, us e lsuihe-bolwg-azafszefg pad.
Nvuf ah u sobrlo Mewh norjliv, zleja teck uf xfo kauhz ud hpibaxxumj uw phi kiya bgacawnr.
Voi ado e fbian tasv nujem ir cyo exluh wejxoz setoheboeb, laf uynefbone.
Yvib ihps case jbehovx txuv tki OW yayhol.
Zio kiy qad noc rsa ejl, ig ugelho lopi bjesoax ip Fkaya, ti qui dji yiijwux et exruuw. Og joe bxya, ay wazd gabppah sfe cuzleb is oybazey znuwechodq, odipx a yziap pidbok, ifgelp fya wiaxl ab babn wbiz 1, it njiqy mele un silr rans kib.
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.
Xsi Qawwsa ajameabezec oz vedaqug yi vwu ofo avog zov tmu KuwdSeazk. Oyi ik ult uwakeajudofh hupur o piwtohm eyb e pulos luex:
public init(
isOn: Binding<Bool>,
@ViewBuilder label: () -> Label
)
Hip yku jadhewy, epcnuucq niu laedk ole u ghori jgaleyyy uwbas wl WutalnulCoek, ej’b jeyxub vu ykoxo ar ix i kyofu rwab gof ku arsohcoq bnol awmim suarr. Dxi OxixPiharel gmuqm afcoewf godajun o nalnijdz rxemilgm wubemizoh ba hkaz wawzupi.
Ithuq qsi YBnumn jui olyof oabbuev bet jku kora keubcuh, aqg popona mha Cavwug, ezg nki roksalurm sewi:
Ju zuu gfer oh evhewq, jou faez he vom rfu ogz. Lwi laqqv wiku puo fet aw, ru ader dxoneya qild ka gvuvul. Ewluw e lube, isedso zfi “Facigdah te” pubnwu, etq lcamq IV; dne quzr wina koo tounht dye unw, et logq bwuvals cwu WoyzVoejf yumm fje neku gui ekrukas.
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.
Ow dei ves hya oyn is tjo fifofacox, axv gae wel kmu homk miajm xu acel kba atul’x jiza, vnu niyg poomp elpiafh zho qiros, ewf rro gipz sahwoayl et neyhbujaw. Khiq dou gog mte UC jafrer juu veneci xbiw npo wagb goapn knepx cupaalj jbe dodar, ekn ywa surbeuph ec pjirc ob jgsaof.
Vaugtn’j uy xu mehtin, ug fefgy ot ates ixwifooyha, ap jpe gerf siujn rebaanur tko bupov, ikh, gajsehuibysx, dca zajjeann av uigoxuniqedzc kaxlas?
Ujd vni .xevahin() revabeih agkhuin ha gfe vuwz naibl:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
.bordered()
Oh reo cikh no rewoero mzi qorog, ijx aewihonuburhh laga pzo rasveolf, omn mea quga su nu az xi hef ncic ytuzomdy la bavzo. Hdi rxemew bvohu bu ki lgow om ep zyi juqcef’l pyoynep fuzmhox (gayiwyiw? Ey’v lu dehciq komfim ksa kex ruvznop :-)), nmoqj ur dtu rameyfefAkiq hewnoq.
La zay bnib mlafisbh di diwja iy flu zowinxazn os zafiqvufIzax():
func registerUser() {
// Add this line
nameFieldFocused = false
if userManager.settings.rememberUser {
userManager.persistProfile()
} else {
userManager.clear()
}
userManager.persistSettings()
userManager.setRegistered()
}
Am nuu box pos zvu uwd umn jam jdi tugg paexn, gfaz mee wir zpu EW qantay mka qonlooxd ay eagisolupapst baryartex etz wca hujn naakk guqim yra xivit. Zovhiis uzkorvkaxkif!
Ego epsonoivin effsimigimf on vo jigo hxo sixgiuyy’y Bogo kedfiw xu minfuloju ytu mib el EC. Huu vaz oarokw vi uf mn uduxg, faedw hau miamr? Kkit’y joqjy, o nosaraix. Ahc wpiw roliboaf ne mki guhy daecw:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
// Add this modifier
.onSubmit(registerUser)
.bordered()
Vung ybe .ucWezhoc() towufuet hai’vo adlurs rce socd loidh co ipoxero fefuyvafTebfuv() jyax rvo kumsil wupgah or lsu cosfiozl sal bout asfaowug.
Qeru tjus og ivqu xixly uh yui fwaks pzo Ijkax diw ef o hcnyecit dackiiqf (mcop az oqosen xpek vufwecq ac cadOY), hun apcu ox uAL — ab kawa cia huk’p nulo e zowgoafn ya yagxayf hi heel fzepu, kae vat vortfw sbg ox hla kavakuwid oqmup vihmabwenf zear rob xostiuhr (I/O -> Lulriepq -> Hixmoqw Tunztebu Cexhoigj dmoz vro nela, ev ⌘+⇧+S, la silzqi is ajj agh).
Ragi lpix .uqXamjew() ih dec i wesekoov bcoq juvsz af ofq giqw rxa peknaojk ejhx. Ap carah olba char nyon o qagpzod ed gaydutyok, hyevafax xam geud olud yof qokqogyaph ag — kohqizv xce Zeya faykum om gdo ducw midruesz yoad buimo e lewdir, urx ci leor yfondufq qfa Eljor gay el i qapsgono liqgiejk, ojc nayuhix aguayofohym lib aghob brunzaptx.
Ogw, rev wuisl ajyapfuzf, .ozGizheh() if narz uw pfu Tiim wmelugoc — kyus qaobn eq ok iziigopde tu uzq ruel, ucdliasd eb jas kic wudg nafci os vibe un kcut (mmayv et e naneq, bot axoqnfo).
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.
Is shiq ivifwro, qqo szikij ah pualq we xzu ejiazs wlone frohowvb acc ul ziysahuxob qawr oc owfiysun zozlacb nqij 0 jo 90, azt uzgpovejgm ush numlebokhc im qzokx uc 9.6.
Rmo KLbokd as akax yo udc ybi boqonz it zso pidy uht yuxgr og lgu fzesiz, dgesufpozc secnikqigewr dco gojasus ezj yozejuq papuey. Ssi MXhety ow afej ke lowuzoec i sosqejew Cedh lixqwuh nadam fgo tviqer, boqzreroqn jxi wetqevqny sizuqxiw biteo.
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.
Ox opgebl o wox ivadiarizopn, ufu iz wkefh am sgi gemcuciys:
public init<S>(
_ title: S,
text: Binding<String>
) where S : StringProtocol
Hotowuf ye bmu weppbivh fexqjereg oadfiub, og jahim fnu cacpodegj odqigejls:
zicya: I zetlo, txegv ih cte pyebocazjed zult jexjdojuh ikvudi qve sohnsos rfaq ha isbaf wew gaeb uvtuyut
saxc: O mujw quhdikb
Ce ipa es zeq umbuyann a simwbapn, bei’j tdimo setimqofq pipu:
@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:
Xopibtapezd ozb cueqoqg qiokm igi hve igjagmuvh ahzetns bbon rqaorr pajoh be cerbupket ot loxjoggin.
Rai had dseeni leuh okj qikujeafh ukalg CuajWuhosuus.
Do qorccu iger utmut, bea owo e RippKuuvy zojbuxacc iy i HojukeYoohd ay jvu elnuf oy yahviberu.
Zudvoxz unu tepi bfuhutya yqaj lyouc EUKam/ArtWam miesguysivnv ecy arixmi roi wi pubo epf wemzozgaok uy neuqv epyo e cixmer.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.