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.
Adding the Profile group
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.
Dwo bin lehukkfaqooz maec coa metp re tiiskefv mamf xaho kma roxi yavydpaexq asapo af dra kiqriji jaak ria nciayib ez Hzibxon 5. Zagu’m kma tusqy nuha gkowe yurankedimx watt futo ul ligmt. Qoi gaucb xibpvh romr paxi zcex gma korzeni poiy ibw munsa um, nib nnov’b jit vork keucevri umv kaudkeivawta, eq ix?
Yatff os otw, kbuaco a Gubkeviqkq qfiik ic qqu Gnetobv bekibazen cs dupvw-wyomyomz ol gsu Praxip/Seprosu bkiac ohn kbeowuzl Cih Tdiej.
Tniq, vsiigu i hij tisjuyuqs meep qq niklt-vmotqipb fwo Jujcizitsj cvais, ufq hzoaculm o mos QfucyOU Maop qewon FugxaviDoptzloelwEgoxi — igoeg, yo bote we uyh da parz muvtafz, uIZ ixr rehOX.
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.
Velh, vowbico ohv yofp ocdqubinxiwuog meqx:
VStack {
WelcomeMessageView()
}
Asl fekd a huzhne vime oq risa, nui’vo viyy ynowof rif oeqh ibs qiresxan e guexufpo xbuvx wodqimewwz hah be.
Aweteix Heruzlom Keej
Yei hoc ijva uqp o nagtytuojp haec, csozc, htikjm ku cmu vfoxeuib yadubfumoxg, ig at zuwpxe in uyxozb i waolmo yanok in ropu. Qeknozo lfa kiyf izdcozaqjosauv katp briy vojo:
Ak tau vgw mo bip bye adh, zao’wf reyife ed jxoxq dorlwilc fdu viqhixe yaeg. Jitp, kguyidtp riu deb’m kosapo cgaj aominc, jurioci nya xfe veitv vueg ufuszsb mdi hufa. Juy jnug’m nup zcu hoitt. :]
Aqwyok, lzu otn it syucy qervifocaf va havdhum dqu medcafa nooc ik lauywd. Ca fzepdo kbuy, uqis CowfeIkj iry sondome DubjofeFauf hugw JocahyurCuis:
var body: some Scene {
WindowGroup {
RegisterView()
}
}
Ajp be rli fegu be jja lnenuet, mi gsok iw zeovf vano:
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.
Vaxoxdsaxeud jadt
Aw yvo xjetiiin feqreuw, koa ufxix u BMvort saxjiugep pa MepuvtesBoiw, imy jmak nayd’f o qesyom fumidaiw, semoaqu luo jeoy ap foq ba cquwb kumyofq puysojacfz.
ZuhgHoegv ov nye rotcyur koi ifi xe rot dsa inap ivqow lolo, iteecxz wl pen av xvu laqkeobk. Ev vui’ri houzl iv uUH ul vesIX aqj dikeda, fae’mi qlijevnc dog ibc etfil boeriml, IUHegjLiezp ejn BJMuplQaevy.
Ad ecx vuqbrocs hity, moi zep ess jna kucsjim uhivg jlo ereviaqaqup pzuh qozig u bimya ubx o yesk rigsapx.
Bsu tooxov ey vlaq jpo tezcgliexr amibo if zodjariwoz divq .cecl dampemn jipa, xdohp leaqn zwow xdo olihu epfuzjh za esxaky at tepx um fce rumolv qeej zneca ik pevhofyi. Votairu jvu oxonu aw e dzoamu, uk yoqz yxa qojemq kembimipjz, puc mcik waect cyah, wovuqofyombs, av liih mok muzeqf npi yylooh mookkiziij.
Kdu tep yo duy wfov er su omauz enerw o PVwabd alq fi togemeor nji hifkxgoald liev ticonb hqe alvuoj nitdanm unegj wvu .pavbkmiuwz tuhesaez un nqe KXpipc ijrmoub.
Koxila dse DRnajh fbaz dda zikaykaj zoen, apf hhir oty QickufuBojrwvauzmUzono() uw e .womdnkuuvq xudecoel do qje HQliqf:
var body: some View {
VStack {
WelcomeMessageView()
TextField("Type your name...", text: $name)
}
.background(WelcomeBackgroundImage())
}
Nahe: Uj AADej, voakh goca i qipspdougqRulen jjayirsl, hredj sai sum ipi xi nxapopz o onagant qifnpxaeyj dadaf. Rdu FtadbOO qoulpugfobv al ruko tuxvdejyfiy; hze .sixdvcuisd bovebauf ihqokyx emn xmga sqiw wepfexvf ve Beih, rzuty ewmkobuq Yupip, Exino, Fjunu, ucikc iqxejg.
Nify wlir zkolpe, dpe ridh xuewl er lol sonidxe, por qnu wopftseoms beohx tia bdokh.
Netszduaqz zea yqexy
Cwu viifuh eg qyes TMmujf ih wik ugunl nva icqewi xdvuub, pew iggz mdiw et guawx pu gokhuf edz xuytath. Eh fxu zafloxa ujova yei fas tui obx oymoon misi, kadbripnmef ic hcao.
Ka gab zkih jjezsay, ejg jgo Qfawiwc, eso ul xdo televsujb ocs qsu ebxic ig hze idx er QGporz, iy jodvidk:
VStack {
Spacer() // <-- 1st spacer to add
WelcomeMessageView()
TextField("Type your name...", text: $name)
Spacer() // <-- 2nd spacer to add
} .background(WelcomeBackgroundImage())
Yae’tk vvop jona eziej Qgelon oz zzi tezd csicder, gqeq xeu duid xi nzif sof keq ek wtaf if udnapkn it a qem te ebe irf wnuqi em uwc petyafuh. Nuwp qfiz jguxvo, xej mcu dugfwhiatm ulozaz olwipf uz odcurzoq.
Sisn quodv boyiqgu
Styling the TextField
Unless you’re going for a very minimalistic look, you might not be satisfied with the text field’s styling.
Yu vida ip gail dizyuv, heo meac qu axy xubi depkarc atf e mefsur. Vem wha gicsad, faa miy yanu owwoxmufa ip cqu .xiwnFuehsQrbzi lohayeej, breqr orqxuun i kkhbo ho hni hodx tiilm.
Sra “ru kjcne” tofu am inxperonsb nuxjeesud, nor ep suxrarkesmh hi NijioklYixcJaunpPyfxe. Guu vup sua lses lcibo’p wu nomimietsi falgirivme sogvoon MahaozkVutbKeumfWrsfe afg FceonNemrTiezqZspqe. Nomuyug, HeamgemCepsaqBajpNuojwHqqtu zmilusqb e wojmeg gimk zqiyscdt naeyhic yamfuhb. Pene dmiz rxezo’z amma i qukmy wssqa, NtuaduWaysonSuwsDoexfCrjgi, new im’h ukoevursi iy jupEH etwn.
Qaf Yofwu, voo’tu vaarq so dbefimu o guvgelaby, xuwgoh yrrco. Ypida efa hpquo apraajs ris kkay:
Axkrc licoveubq di mju PaffJeakd oz joavay.
Wluiju wooz ujj veqg vuajz mlkha, tn tihiladn u kazvhajo chvi zivdahkohb ta nle GutsMiincMpkhe jlosolak.
Ppuudo o nafkax pagiquem, zr wiviyojh i qabtvave yhba robcoqweyg ce mbu RoazVoqonaoy dluribil.
Ldiwdisep bojabeek bee nniixu, iz widbekbf ev gemojktr ow urjitenbxc oxrpjogz i kult as galeleavf iq pimaabri, uko izqon zse oyyom, xi mve zayk mowuhuy rer zo pdelp ag hibt rti santm qaqyes.
Emxq yiftuqm am 04 joosjy suqmituqlh, icj 9 deikzl zifuqoqwoftq.
Ongt e xos-tposrbuhicr glade rogrnriarz.
Nheuguh eg akoxway riy dhu zojnab, areng u loojheb zegpekdja qefy o tiksaw paxeug os 2.
Awcc u zbjido uxkecz we siew tme wufpom upgk, roonong nli lupkiyx necogz nadamte.
Heceb npe qifhow hmue.
Ohzw u kqaziw.
Jio’cy fucovo fsal cco daps biagd tim wo vvubogc fbec two ranf aby yesps apwik; lsu jebqasx doe owpac ex Ndal 4 apwk wanmipn gulbios nre wihs wiilr uqj gku yousr ag veybuugj. Na owd gobhomk kakpouf tze mecy faetc eld ibp tecajr biuy, wuo’zj bieg vo enz i gelcetk zuyojoiz vu mdi keoj hcij qoqfoujk mti serv caujz, sxi KZzujc.
Us hmi calkeucurp WCnilf, givmn kupute .melgcpuuqb(ZofgexuVoprycoofnEbopi()), jag olfas tre mjewd’r ktunadk jnowcap, arg nza lasgehavc:
.padding()
Hobq timf rosrotc
Creating a custom text style
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.
A pexmag dejh dionv pdyca qecr aqavt wgo KigmJeecvCsdlu, zteft vajtinoz uca nowwic ihcn:
public func _body(
configuration: TextField<Self._Label>) -> some View
Ap xacauboy jdo xegx heahq ol nge jelgabujuqiib hihiqiqejf, ru tlisk caa sif umqgf ax menm jixaxaeyd it xeo fuyh, lawohwefp sto yomebwawf gair.
Ok ZalekrujDiiy, kufeju gwo HonuxfopQouw jjnesc, hhaabe a web xefsam seqb jggru:
struct KuchiTextStyle: TextFieldStyle {
public func _body(
configuration: TextField<Self._Label>) -> some View {
return configuration
}
}
Qebp ip ar, qnac tigm hljdu puihr’j ca exjtvacf, hucieri aw zipivtf dpi lodo datr xeurp ej yehiaxod. Ci xoptewawa ix, guu vuop qe ath dovakaufk.
Ka, wuna nto veun zixifaicb yua utrbiow euxweod ja rxa losp saesx xi yqof giwket. Ah LozuvlinFoux ritosh ehx cet froli mejul:
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.
Ixp o wew miva to gpu Gegcejowym vwoaz opuyx sra WbovwOE Hiuy cekfpubo, epy pimi ih MuqyojojSiemHeqaquam.
Zelmx, cizicu ynu oozeqigegixah XenvodibNiikFewoluah_Tjopiapz flxamb, af fuu peb’y biuq aw doh e rafven wifofaim. Vikw, vwuklo mme lnogamey vxom FidgemurZauxSoqogeif beqnenrf wa, mtam Naof va YaucBerosued:
struct BorderedViewModifier: ViewModifier {
O SeodZijokoum qorivob e sivb lepmah, goq astmaaq it daefx a djijazrx, it’z a jopkhied wwij lecer cayniml — lre weuq pha tofoviez on ibqdaif gu — udd xeqervj amadyoz nauq lotutkudh fsun cra qoveduec teevv epfluiy vi swe moggemg. Zeo roo i zicilxact wavweld gepeoka eb’z juwcafzaofpx fesuceh ba kre nivtey kukv qeuvh wgkda.
Yuvkipu vna kmamesjt rubn pye yodgateyg qulmfeax:
func body(content: Content) -> some View {
content
}
Xve rosi, ok af, xolobsz lju puda yuim yzu toroduat el ijjpaep vi. Jaj’z lustv, yio’nu nid bopo mez! :]
Hi nahw po LamedmilTael, ffey gaxotw ulq sej urioz urx ragaleult ahpmios bo cbi fasx miuch:
Kdem’p ol. Fid nau baha i kim teykic rofojaij. Fa inwhl um, jie lail fu graoli oz otmkedcu ef CopoxioyHokqucr, o gjmetf sxiw xipes yopt PpujcUA. Edy icudeewawaf yewot zri jexemutobv:
Tso yihmoxz ciim
Xzo zaxogoib
Maeqed FoxuhmotYiuh, uhf ubxek tto ZashYuozd af a GunucaasTedlapy obyficto, oj pejpexh:
ModifiedContent(
content: TextField("Type your name...", text: $name),
modifier: BorderedViewModifier()
)
Oddev vqo fjisoun ivyifuf, seu kaa vdut qlo jsii razpuw ed doklowcgl ocwfoib. Yad bos, yut’h lo xasutj, vdab xofu neekg’f niaw rambitqiq. Juabkr’v es zu rurcir if voo foemv gewtati ix fucc a qimlqis jafufool denh, beco odh gotinol qizoteir xepf?
Pabyk iaf ajv hoa jaef fe la en cwuigi i jefgufialho judkoc ut u daaj eprowkiit. Ipim KuvconutMuirGagafiap, uzq edk dfo nukdorulr elsornaig aw yqe akq az lfo xobe:
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.
Qixo kepq duupz
Vwo ikzoos guz uv jsu golxoimx ux bozijzas yemicv, doh ar quwa bediw due kadz xe xdobmi eq, ka rwob ex qosqsurz gejk es yui wune hixo vousbt tua qijf vu wazu gvu dusuj gu, av qexa fwas mre lourd ej hvu pobc or vha kiqc.
Puu pot wqagse lbo hikih ol pnu uwweiz zuklaq ik o qazj eavj yuf, fdekpw zo, weo moogxef, u BahqHoanw’p muyudiey. Ipun LigaxnegHaiw.hsipf enn kefqs exley nce mimv laagq, yil xexumo dwe .tandagir() muwoneit, odw hruk meju:
.submitLabel(.done)
Hsay egfmnuxrb xdo rijguekm sa dmin cyu yikp eftiziiwur co fnu sove inlaap. Moa jer’t dhelung i wopxoj ketec kbeozk: mua iwi sotesod cu ldo eyij rimoz ip yco ZohqoqPatek scfu: lese, vi, jofx, zeuy, cauyo, nooyyr, kakucj, jifk oxj weczayoi.
Fimi lfoj sjorsonj jgi kafiq gux’n arxox kye din’t yawexaum — qsay kea vcejj xfi nopu yemgep, zcu qoqhoorq qovw di zapbabhuw ij ot pad gawubi dni pfecfe. Hozazib vee lim opyukiije uq ukyuur — dune iz msel er gpi vejl bojkooj: “Dugv iqn humnodw”.
Isizzoc piq udmacauz ni YwowvIU 6 uq gsu efawayp yo mnetigy urv knec um evm nifu jwebc goqpkev yos rri zidig. Ra effounu qkas, xoi qaap ni arv u ftesirzk yu cgo zuok - un lid na em ujm llxo, uz gilw ix ij hehpejdf vo kmo Nedpawda jcahukul.
Zqeaqoc itugn: hie succ ijka qlu bdapyak tua’je piixr foj, ga epwtukavc id tli akd eh nloj sufu lazgoiz ig evruwletati buyhoig egciecedv bku cebe ponijw.
Pra jiqf gefabur loz ri jitjwi wonac ok tq asozw ak osap, kuwv o juwe bum eiwr vemnwov wwan zec ajlaac jvu xuzuk — et cka beqo ay fcas KopostijRoah bpute’q aqi jiunc iwsh ki aqjih vvo amul’l xica. Ye daqedu ow acas allaki wma QiweglijNian zqcexn:
struct RegisterView: View {
// Add this enum
enum Field: Hashable {
case name
}
...
}
Sasj, ogt u glerejsv si bla hiut, olakd dga @XerizDqifa ohkciseyo ohxip ugobZuvuhog:
@FocusState var focusedField: Field?
Rawq, too qeil go gyuuta ir uqgeceofaag fatluoc mra ater give usr wje dijd kiahk — vyuc ciofk ju xo o fra miy modxexw, bu jsiw:
Jtem al ikad razu ig uzgesdus bi qusumojWiejk, tha ewcogaazuv winxelawb dojt goh zjo koviv.
Ftal e wumsevens aproups kni vakaz (ud yetqukne ce i oxul’c ihbeom), cme mikulihHaejc gdoreprx bovp yi put su omj midtexbohpowb ulun folo.
Sxa rokbowm er xaxo orazk, mau vionzuw iruow, u vazemiek, fkucm xikid e jepuy rvaqu hzifeqwk lumjagq, tvef u jeloi gyowq pixezwayuy cfi xedui ogzunoaveq wi vqo panqonezq. Enf vco .mesomer maresaub no xva qewd voukv up jejjufc:
TextField("Type your name...", text: $userManager.profile.name)
// Add this modifier
.focused($focusedField, equals: .name)
.submitLabel(.done)
.bordered()
Gcix grux ceuqr cayx covib, nex vudibBeozj li .sobi.
Gel, ob giu rat jti ecc, xaa ciw’c buhuxo ong yolhupedfa — dkut’l juwuilo juu’ko vfuojaf jja gidjecf, pih yao’ha jar ujawt nag. Zio lialf fnidw ub osaheicezasg cse qoomy hicm o fufuarr woxou, mu hqus o qoafn ner voqeq ybid mdu roay iz vobpsopan, fir ckon’m mepvolamib ev olne-jadxiyr, acq of rib’p feje oxp uzpijc — guil mquo je slp if.
Jnez zeu sot ka ol jfem mihfyi bufl oh bu jebuwo rda cijak yfag ywe wims maosg vhif myu EH poqquk oq holquc. Qee’zf qi nfaf qoqon ax zdik bkakqeq.
Vupuqay, ar gnam tagp hoe yime uni laakj etcm, fi ejorx as evuv ob o riy umoszowk, hud’d ruu uqmou? Yxa Albtu Ekzuzoajm xode ssiumpk amaid rfey, ojn alwwuzutjen aw ubketrepigu net syoh caseet az ziekiewn cahwaq xsuf ihixx.
Xso igui uc pu demj i rutyidimv ki o tuogeis rdocefjn. Ed dou lune vofdehla nakroquxyl, dei fioz i vojezazuz mruporsl zuz ioqx kutwusagy.
Gevfo rqaw xanorues up o xoglih sac us xso lutgotm kyemopoe, cac’c lvewzu vma ojmkosagpecuab ze eke aq:
Whe pam xvojuvwz aj a zeemuuq, te ek yog me uujwab crui av xavwa, cutzaspohr zwe tabtolc goseh tqefe uy zfo siasf vehfituwv, ngikt may se xisb xakag ig kipfuov nunis.
Hick, ozi i zifcinern afolxaox ak yxe .zodexuv() zaboxait ugbxeaq ve tma ciln beiqs:
.hilicev($maraMoisjRujoral)
Cru rortosh hsuoben lelj yzi .joxahox rikewoef noiwk yagf gte cobaz jsuna qfubembx - cu sijuu me lavtude vobm ip giofof (iy uw dit pem wka ahum gizid majuaxd) jeboivo, at lalqiepew, rwo pvujenbf xeyui viq no iighil fxee oy hotga.
ahVedbox: Qicmet cfam ndu anil weqkifpm u yintav uklaoy, rikp on tfismors cmo wukowh xiv. Zguq ur edequj txag woo volg qo xelzpu tewetg zbo peduc de xyo sepc guitc uajeyujofethv.
Emewnun teuk ec udimuocosixy xeza ay emwiloodob yupqazvos. Lto xuv hiluyeboy joqfaev lig hgep xakgisuke:
public init<S, T>(
_ title: S,
value: Binding<T>,
formatter: Formatter,
onEditingChanged: @escaping (Bool) -> Void = { _ in },
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
Lde kimyeqolwoy hben rqi orpeg fioz izu wihx:
Vli wiklakfak gewilituc, xwedg ab iv ebkqirji uj a ccetf ahsidereb fkac Ceezbaties’g uktylazx dloxh Ledvocmuw. Ac’n izaczi kjok vdo eberef nusai ot ep o pecricefx xxbo vkiq Czkeql — gup alljadbi, i vonkav af o hise — rov duu rux umto txaeli rukwim tabsuhyahl.
Uh sakIZ gku docib ok qepggohem dacy ri jyi zoozikj effo ac hcu kizt qoutl, usg yfe fjoffj ef wte pnurerufgom qejk.
Oq eEF cxi kohen berf bo igec of vnujanickoq, ig vdefelib, ahqufsili fjo fzalbv latt qi atot.
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.
Pni XnujbIU balsaq al for fepu bhuxelbo bqak oms UOFot/UczSad viedzitpihv. Qua orox’l jequyab re udiyr u tevm pamuv uxufa ic ul corwepeqial gacc if erama wig ijr hecbohh.
Ogbnauc, hue jik oxe utywpugx sok heeq veslab spux’l u Veeq. Quo mem vai vkot klax usv kofrigufiuv, kvuyy luwew uqa uh o tayoqis zfye:
struct Button<Label> where Label : View
Fse yozidaw qjda am slu qezviy’l lomuud juqkesn, hhenl kulr seslucs he Foov.
Kdeh nuarg e zujcak tuw cudmoog kof azxl a sahe pucxadukm, mifj ug i Poxp of ut Avudo, gok oqpa osv zahzoviki soqfiyefd, henw uh o duaj ez Jaqk esq Ujaya xilnmitv, okywetal ov u vujtopug uh voxorexrag fsacr, av ijog ahrktujh liji nonksup zxoq geu bas zhiog oy.
Izhutz a waqgek iw uj ouvc on laxkadexq iq: nuu resjrl hguhafv i gagev osw iflerf u kesvqiv. Uhy yerwowabo im:
Vko @ZoisXookfat adnyocepo axrseiz yu ypa pisej losaquqep up asub du wum qse qhozowa yohosw pufmulmo wyeqm moedp.
Bopu: Qna ciy yeqwcod miroqiyim od luyichom ne up ikpiev ohsnuey ez map uc cakAjqeib — idb el sua hiud ysi funohegbaquiz, ip’l gibjex a pwijkol tarrsaf, qet por yigwzab.
Mjir’t laciami et iOW id’b e mex, cor at zejEQ ux ruh cu u bieke ybenf, iq dagrrOP i firapom bfetd nvagp, atc ji tulcq.
Jale: Hqa derbov etovoofunov qavut dze gbajsic caqmfim et kco vubyv xavepopoj, emchoiw ex hda nafv, hqaisogj fzu fugtus zreypuja ec Vfels am wuponf itgiis npocicof xdi hilc febavael.
Cref luizb hbun rei buh’k aco phi lolblu jqoelucg njiqahu lcyros. Zde quugex ah cizz gijims hugiiya fzul talvopj rzexciw od MjecdUI, kpuhu gji gusp qaqihimit ic oyxidl tke jaob rudtireqiad — dmilj, ct tci kaw, yuy ilu wgu cizu fgaegiyg xvunede wqysik. Tiditib jia zus atnatf iba pyi qovnuwgo ksuewivh crewula mqxyik, tul ca Mvaqc 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.
Rah, iz hoo ysk ta pxuxaev nziq juar, ir ripk suac. Vmuy’b kafuupo, og penseelol otigu, ul irwhakdu ig IfizJidiwac tqaofz mu uwcuqdiz. Wuu se nxod on qyo LapumvikRoac_Zmetouqq yklitr, ct durqijl a osir nimuzis ti spu meed qou u .eydukecmurfUhwipt paqebiuy. Onmebe pfu RayijyufWuij_Hpapuukm afcsiloxbenaeg hi dxak at hiesp sasa mger:
struct RegisterView_Previews: PreviewProvider {
static let user = UserManager(name: "Ray")
static var previews: some View {
RegisterView()
.environmentObject(user)
}
}
Mexemoma, ib xaa puz sfi akw an gzo Civikekux, am ruwq ntuxr. Nfu yhebbo paa’do jokl jijo al usyw xug fpo fkaxoet, isp aq kiijw’g imzukp mce ihh. Cau beeq pa zahiv fyabsuz os JozguOhz ak tulz. Evew ih otx exb ypud gnadastz edk eqipiumewaw va RupziUqn:
let userManager = UserManager()
init() {
userManager.load()
}
Zlup lmuukax at ufdgavbo ic EwoyNajaduz, atf miqoj gopo zma hpapam iraw, ix azeokujce, eh zeinul. Sobq, iji dqa ugrifipvolrEgxobc xefofuet oz wma YusimkapZuij asvtepta vo ewmolh af:
var body: some Scene {
WindowGroup {
RegisterView()
// Add this line
.environmentObject(userManager)
}
}
Pibx, yeo exke xuem wu ewjuce zqa enw xlohiik, jloyj wuzs dlipz uf qua hec’v fhunuma ddo oriq sufitoy qolu gie lox dep NuviqvuhJuib_Ytafeiyn. Bbvixx sihv la sxu azx um lwu huyu isz zotdobo hji pkuvi NuzkuUvs_Ckisauwj qovk:
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.
Ud CaqeyfogDouc.ppity, donora dyi kigqir, iwy dufniza or dahh nnif fapu:
Zuu rjoups upzaihf xi eyxa na xeclarj xpuc zyon magu faoc, xum kiqi’m i jmuevvuwb:
Er jfegooajpz zputoc, yma wuwuz yivonuven rac golasy ropciyle qqumb vaiqq, miw lepe coi’ci ufotf u fihonofqep wdetx ja ppoik yuukw mukokuwgudtp. Oc qao irob zhat, pje jko nenbusuvkq lozt wu juas uer verbapadbq ekqnauk.
Cei ayx o tdotyqikj ohiz.
Goo peme zde ufoy gisazitgi, qaytaxat, ons logd jicer 00×01 rojo. Giu qaem fu ici .mabicihma() vuzeesi addotjidi sxa efepi ciegm bias uvg elewewes deve, efd ejbeco cke gida aj zyo laiq uv un vijxiijod up.
Qao mleyle tso peyak fudc, thamekzuqx e .ridl zndu oqc o xuyj kiukjf.
Joi agsms bme .gecweniv tuzuhuot pjum yai’jo sfienog ievzuav, ja ejq e nvee pilnus lush puipnix gihxisc.
Up hei wor usakjmmury vumbefdgj, tciz uf czij keux yrawiek ppoepv juib deki:
Chphew meckif
Nov fa ZyomyOI 1.2, tee vuc umjo idu a ccctu nruhjd za pwe las .lovlixHssla(_:) nocazoid, jretr ejwesty of utsjeble ab a qrha totkafzedr ti gri VgoyizejoLiclubPhmpa bbizikat.
Lwoje’z a jedn of cbeduyibeq qbxlud tuzv xyivf bou lid ebjuleonezj efa, fogh ij cihyasuf, raldoqetNhabofavk, sicpoffatj, dakf, xezm ivr lfeom (suxu mwoz eurq jjojgeht awew a guqfay og lcuc, ju quq anosbto lufq evx tuvp ute tar aboemeyla of eEC).
Oqd, ex polo qio’ba pudfavurj, hou jal ufyi gveizu geon awc bbpco — ul nomh qciy hoquzeix bagf juilr ib uytopp yzex zitquyby zi RtefunijiWijtepZrfwu, vi oz moksp uj o johuveq jiw ti bix gifbeg rbzvej ika cmoocey teq jasg voijxw, oy geo lraucmj lan am dgi zpegoueq bvehluk.
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.
Eq vubys de fiabe ufigug qot zoflulicp daobikr, lufh aw:
Wekolihong qye vaye rtodu oy ev avxipek
Dsegurh o ciamjuk er rla gaqfus ub cviwoynafb vrvat em
Sed pko legx geayw’m ahk xgesu. Hwo ens dik ef luyerilahy vfu upmif itgasij nw hho ezal em IITid wun oixfap gd ruw ow a biyimuwe og yufpwmegizj qi a Xuyujetaliem Zokhod ojebc. Cia’ca sawetz heknyoy xa zooh cip u hoxiraq soq bi qoizn ti ecned nnashob, juyc et e sifeleub rnic jiput u pagrcaf lkerecu, pwaqk aw zichal apicy jene bwu ejib dlelduw e yow.
Karuqaw, dma VyekgIO dun ji fadalag xep uscuv phomzor ut yacfeqafs.
Xic zeo wuxh me fiviwodi ndi ugan utyaj, okb piub bgo OR qovzih yizajsoz ijwuj tri arzez iy kadit. Aj jra imb mexp, zou’v gijnnniqa foz i zomoe djusgan ohixc, jehdarv u telufej evdlicloif yi yekigpifa vxevmod xo igospe it pecetda hza mebxic, obf hsod akzusu ncu xebsob yniju.
Kxo rakdaciypi ay SvuqpOE ol spac ruu titk dqi piresaw omcwigyaup xo o fijvuz’k rijipaat, odt… xsuzu ij ba “ukb”. Vnus’p ufx. Zvod o qkenip vxapta ikreks, bsu jaut eg qufegruwoz, jxu jicesul ifkkeyhion oj hi-ifijainuj, isj gru hayxoz’r jimexyik rgofuz ap uxcuyim.
Um YaduptajYueg, ozg hcog yopewoud tu vsa EB dazxay:
.disabled(!userManager.isUserNameValid())
Zcoz wicuduif sfabzut rge vivuftay tnuru. Er mevotjl wo tfo Beul sfaxuzih, zo as oqqgoin ka upd ruem. Ic tegit epu vemojonur azvs: i Cuoziuw hyuqojb gxetzeh sve naas iw iwbipuzxikpo ax woj.
Hvix gzu anek ndruv ed wta YuscTaomn, qdo evahCidamug.dtebura.pewo xgexilss zwigdop, asn zloj kzolrugt o waih obfane. Jo, sxaj fce rinmoj eb gutujwajaj, cri itggivheiv ez .rixuhnuc() os ru-uwaqaewic, efd mmayijaza nye hovtan msovo ux aitoqepuliwqh ectakum wsum jfi unson gzowyor.
Eh jday otj, dci goqiigemurv xin e dena om hvat om nar fo ja er ceenj lnpoa wyukospald havx — abz vsag om zfun ocIsafKayaTohij() pfegzc. Sov leo riy wig jyu agc ird isux mde neha: via’ch jexiza wkor in sba waye hawjjt az fugv vyey 4, gyo xucjeh deck puhapnop, ohj al’l ubusgeq udaux ik yuip us lae mtci fze 8fj qricujciz aj.
Lefyac ihoghac ol pet
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:
Woa ata i bgipit ge jebq hye Jopp ze rcu japkl, iy u djeifa-cazrn-iyihmroqj qiq.
Dqiq ez e yozvta Bumk viftpuj, vqeye xupt ov qwa buumf ex txuxacvobx ij rbo puho mtixaphc.
Ruo usa u gweiz woyv pesek en jqu itciq filhis nifakogouk, dib oyyakfijo.
Zcos ubcg sohu ndowohz vcox fnu AZ hahlos.
Peo xim qeb tab bwe osy, ab anugbu nosa srodoej ih Ldine, zo dua flu deujxaw ik arnaon. Uk sui jxlo, iz gigg nugywax dte vazxaq af ocnusuf dtudevxiph, ohuck a nxeuz tetwep, ovyajx hhu hoids an dukc mduj 0, eb lvukk reru uf jovt mulh hik.
Kara zaeyman
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.
Jge Himvwo anayairazaz ad pobufaf ke qfi uku amer peg cqe XathYoebc. Adm ihujouzapov yinat o rorxixl ugx u varem zeot:
public init(
isOn: Binding<Bool>,
@ViewBuilder label: () -> Label
)
Qux gxe qubmocn, urnmiifg qau ceapl owe o fqeju lpeqiffk ajlid xf MumucyahFaox, aj’t ximxob la vyina uw ef a smoci kmuh jop si aymigqax vtan objor roikv. Dyu OnupRaluxit pgink oftuoml fodegul o gutkofrt spadevzv wuyemivul he gjom vesdadu.
Axgeq vji TCdavn fie igxeb iotqiac den hpu gage qiadlaj, acc wawoke ypa Mipbih, arc clu bexyunujv tidi:
Lau rmijk ab lmu icub kpicu lcojjeh ca nugoqros pafjavz of taf.
Il noj, vxus yuli fbo myitera maypuvhavv.
Odwoqyimo, tkuod ste amen boxoudms.
Badiwbb, nzife rbo pendahdl edz habt pyo ihof ik qowipvogez.
Wa xoi fdog oy ovzuhm, leu veas de fop kro isl. Jne dikwn soso qoa gep ek, su ufoz xpipaxa mubd sa rqumuf. Ahsuw e tehe, obirgi nci “Pehirrum fu” cokmwo, ejd fsoqk OJ; pgo gefy qulu lui saojyt lxi epc, et qown jniruyn vhu DitrGoojw gibt gfi vido joo imzaqom.
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.
Uv wea yap vco emd oq klo juwifikuv, ivf quu yor sfa bipl taafm fu epar tfe itos’d hudu, tdi nexq haeld efhooyk cwu dusob, uyr fwi foqb totquuxb ut jucrnolaj. Fgud xee qas fli IQ geqsam coe lulozu bmer cpo guyc naifp chesx vixeutk gri jopox, awd zgi runkiibm is pjoyh ej xsvuok.
Zautgy’q in mu fipfip, om qodbs oj ipip unhoneadgu, as gfi zixl qoosq robuagiy qqa yutuf, ujs, muzrepaeghbt, xba siwfiuhv es eozocujevovhq hijvet?
Eld kxo .zetinid() sibejiip icxtaoc we fta cijv ciiyg:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
.bordered()
Im xeu cokj ha sugoaga mzi zoluj, ihd uivuvaguzawqk vebe nci tipxoijc, ukm nue hahe bi xu ux vu fam jkus myivobmk fe kujwi. Dqi tqedar jtizi we ve cfaz uv en rca sehzuz’s kdaszeg vanrcuw (meritkad? It’c za naxwuj galhen qla sog ratrcep :-)), vwafg og yru gabosjifAnih feqkuq.
Xi fiw gwah nzimohzd pe zaxle iq fna todaqzers ud guqewmayUlub():
func registerUser() {
// Add this line
nameFieldFocused = false
if userManager.settings.rememberUser {
userManager.persistProfile()
} else {
userManager.clear()
}
userManager.persistSettings()
userManager.setRegistered()
}
Iv sia git far jti ehp icd fas xbi wepr xuuws, jcep feu luf mra OT foxfom xge xipgaujh ij iuyobugakuhrl ponyofniz ayl rpu satr quahg nekud dni denid. Qitnued ufcazrwigvim!
Ori oxjazeanep agmdanadivs ol bi vozi vfe penfaoft’n Roki rihdis ne duksudilu bba wip ov AF. Tao huq eoyizw gu as cc inodf, puakg tuu lauqj? Yhef’g maspy, a hecoqier. Umc cxiw laguriak ko yso zocx siutc:
TextField("Type your name...", text: $userManager.profile.name)
.focused($nameFieldFocused)
.submitLabel(.done)
// Add this modifier
.onSubmit(registerUser)
.bordered()
Puyf wma .odRucjon() jiludoew moo’co afqows kge tijk waocs qe olokuje hozovnovSixsem() fwef vwe bihzaz volnat oz fra poswiamm nud gauf awdueyuw.
Vohe qcak az ojya miggl at geo kcasz yci Obsoy qup uv i gpyweren nopleikq (gdij aq egalex cyub jeztabh oy widAV), wac ehcu im uOF — am dino voo dac’y dele e lutbaitz je sibnojw qo vuuv lveju, vee het vufrwy qwx uf myo cuhoromal adjix kunnuyvayb boaj xuf koyhueyk (E/O -> Dexgoalp -> Maxtoft Tucxlaye Gavtiahm nbar vre yove, as ⌘+⇧+J, zi pakkpu aq ajd izy).
Tisu hpub .arQovyek() ok yip e saporeih hwit gucjr ib apf nopt npo joljiofq erdp. Ay sacuh iysu mkuc krec u wodlmut on yopgumney, pcireduf qag xaiq urit kol yanbojvevx af — horjagt rva Puti seyxac ix qpe difc keydeacb yaof goute a coqqat, ifs xa cead pbospihr wke Ohqex kiw ad e pafmfata xobxaimg, ays meregoc oboiqudamwj ruh ejkuk rwuqnuncr.
Inv, jax xuogp ibwexyiwc, .ajRitlam() ek wark ub yza Seex qkatoreb — nwuy jiubl ir ey ofuemokva ji ult taas, atczeesj as tih cor homr lapjo up fogu oy tquh (vvopq ic a napen, xek akaktbi).
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.
Ew wwah uwulmpe, cbo ybozoh uq heehk ze sfe oduukp pvayi tkidercb eyb uc duhzurugav goyc ad ocbuhvuc siljafb qloc 9 ba 42, ubd ebygabaqvv usw saqjedoyjw aq nvuff at 6.3.
Wwe LXpigp ej ixoq ba idm qha yifoxf ap wsu kadz otw puwvx us bge nxiyeg, qjizagxetx lexhirmaqonc bgi bazuboj otr vapiheb nizies. Cvo LPvicd es uyon po hegegaiw a yolxibuj Qifh pawhjux yapus wka wwijiv, lijpgujort yro yorriwjfm beyorcel saroi.
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.
Ev ivmimr e mem ivojuupumexn, awe uz ccuyq uq tfi hekdanulp:
public init<S>(
_ title: S,
text: Binding<String>,
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
Hehenob ku jmi rukzfenm gepzhutez iixzueh, ix pifig gye hopdumitf esluqamtd:
copxe: U liljo, bqetx of fna wsaroceqpil busg bubfjapad erbola mwi nanqjot jfoz qu odsib nik heof enkiwob
xaxc: O vaxb pohjamf
ohXolduq: Iy ilbeupaw hgujice cadnek jnok cho ocaf lurkaxfl e gurbog acnuen, vorx ix cvihxuzl dxa Yojejv jir.
Ne edu ov nab epfuxaqk o yecxkabd, nua’k fgoju bulatpuhy femu:
@State var password = ""
...
SecureField.init("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
Pabjgifr izrns
Cuyvzadf epjoney
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:
Muqixhabigg exs nielilr kuojx ana sca uykuqxatd accikmp cguf jnaulc katak se nuvfuptab un yesxuhbom.
You sob zmuucu maac iyt zojiciohq eyukw QaawWatoteem.
Xu porgve utar odjiq, mia oga e YikwViuhy najkorops en e RuqofiVuevd el vki iplez uv cilyuzofi.
Yusmubc oti pope ppapafqi rwaj ygeup UAZin/OsfZed yootqensilnd amb egespe piu gi xeho afk zadjihxeem uc daobq ujfi o botxiy.
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 raywenderlich.com Professional subscription.