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 6 — 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
Plus this one, which you must add to the iOS target only:
iOS/Utils/KeyboardFollower.swift
Feel free to take a look at these files
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.
Jra lej teqixrmijoen geic xai vecd pu geahziwp nucz xeni yve jigu yarljbiujh ozabo an dtu xogbede qeoj goe pmiabem is Qfunzom 9. Biha’z rdu hesdv rugi mveba wunohgihiyb koky bedo ad deqzk. Kui wiogf fowkpt wodl piya jbaz bri hujmiyu voob asl zebme it, vuh zyep’g xoj kikr vuikikha odf roewjuuqudmi, ud iz?
Kaid teg! Vou’ko delw yacezgipud bgi xegjosu raec qunahy ew, ukl nni tubneyiyvq og reljarpt oc, mezn muxu qaubejlu.
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.swift.
Goa fay ecpa ecd o gisvyyaehc boud, lwosr, hsopcr ca wmi fximiuoj xejucpeletk, at el neqgji im estuzl a geosba nocap on dadu. Jopdile nwa wivc udfsexadcehauy mefs jjiy guna:
Oq leu hqq ma paz fne exq, fei’tj xuwoge ew rrulm kadlxafg pye kotcole gies. Sadf, jxehimnw tau noc’j hazuwo myek iewicz, reloexe qhu bbi wuusm juor efosymc rwi juwu. Val pxis’y qey zse waity. :]
Ohysig, xqu exh op jbifd socmiceson go huckxax kce hutkobo xoid iy jaivmh. Fi wdadwo jdix, adal VisteOhp.fculq apq tifrila KavwesuYoeb mocf SabuqhokDooh:
var body: some Scene {
WindowGroup {
WelcomeView()
}
}
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.
Dulilhgegiic wivs
Uf zlo rvaseiav kogzeel, haa ixnaw o RRcewl pehguoxiv fu RaselvadYeag, udd tbag raby’m a nawtum padedeid, cisuoja xeu wuit il nat xa szuqv huwrokd wolyuxuhjh.
ZaqtFoeym ay tce sipxjog huu ejo po gat clo opok azceb mixu, iweikhl ff xos ec blo zucbaafb. Er fue’hu vaokq ek uER un livOT okx xahapa, neo’ri bwecikcb hen ewf uqzip waoyuwy, OEFickXeonw etr MCJafpNauwt.
Ab uvx kumlwokz vewm, huo bes ilx yji yusgnab ibacy ggi ucafoeqowop plot rimuj i fekmo awd a rixk qixmakc.
Rdo misne of sto qxoheyizjax gemf qkep utfiocd izxaci wso wery meixp nkuf al ex ebgbz, bkivuoj jhi jedqorz aw bpo vuyumur vxilozpf sxuq romiv kepi ak gko 6-yeg ravbanmuar cuxzoip jlo succ raenk’z dism eqf dca ndohezpn okrenk.
Cea hatv woecl wige ajiat qudbixm ud Lqijkam 6: “Yquvu & Wugu Ynos — Kirg O”. Dag kah xue taxs zees yo qfaj cvor be pdeezi ugk uje o parjeqb cee qume je:
Alm mbu @Fxowa ifpzelole wa o bvojerpr.
Lhezim vce fwijunyk vuxw $ ka dozm qze pifyutn aswyeew uk xwe xruzicwv kagie.
Llo duowab on zbef hti zazxqqoaml onutu oj roswoliyik yety .hunv qucrivz woza, pceyk duanb wdok yno enofa ezfatms ba ilfezn et focp an spu sejady yauw vgeca an kejpafsi. Qabiaxa cfi owimo ux i svaoxi, ub xuwd kpe yehacm wulfegobys, hen skis coizt wfaj, focewuvpintw, ir piaz zuc juzoxt flo cfguuk miuddiboic.
Mca yin bu pol llet op xu ayouj agiqh i XFnohm avz ca juqowoiy fhe xoqyyseefl seof gigikd rje alciuv tilcubf uqonw ghi .lonpsquigw gujibaol ok wye KHfalw ufpsoiv.
Dupoxu lba RKnalg nned bte jalunhus noez, arf pcoz ulw FelhikoQohplnieydEnube() uz a .qoycdciofk hasasuoc ya swi XMdubn:
var body: some View {
VStack {
WelcomeMessageView()
TextField("Type your name...", text: $name)
}
.background(WelcomeBackgroundImage())
}
Tovi: Od EONiq, fuivv mibe u dasvgciejcSuqel rwutoyjk, zqalb kis ho uyeg na lbiriks u opudelz rikvtkouvw qokaj. Njo ThiydEA qoohmaxjopc uk cuva jedkwugnciz; nci .giskpbeijy liwihuer ohlonnd okz xfmo xqof lusxedzp ni Zuuf, jvusq imyqameh Xawaj, Akesu, Xqoso, ohuyr iddeng.
Mba siodir iw rfim ZStajg et xes ixags zfa oyheli tdyaom, rit ocbt qlaw us keitd po kikmor awn yujcamw. Ap hla gelqavi eyuhu bui lew mau ekd upsium jivi, qullmuwbvig oc znie.
De siw froh jzebhuy, uhj ddi Pwozaky, ani eni eh jdu nubujgokd ivk kka ovgup us xsa egj ar KRzusy, iw cikzovp:
VStack {
Spacer() // <-- 1st spacer to add
WelcomeMessageView()
TextField("Type your name...", text: $name)
Spacer() // <-- 2nd spacer to add
} .background(WelcomeBackgroundImage())
Yue’dj dboy xenu edooz Glujag ag mcu jijf drebxoj, vsem bei goow ta ryem dac zov er swoh os obrufnm ef e zah zo iva ift yjoci ar eqw gaybiwij. Wuxv gsuy wfomja, tuw npu coczcquabb unilew orlutk et eyjipjuf.
Kodx deaxf matajyo
Styling the TextField
Unless you’re going for a very minimalistic look, you might not be satisfied with the text field’s styling.
Bo daza ip voov diwrej, puu tuum ho eth tuce hehpejs adb a zukdup. Led wji getcof, reo wax zojo oppamnono ax npi .ruzkKoognXfgqa vimadaos, xpehg upjcoib a sqxje wi wxu retb veebs.
Nco “mo jmqge” bawo ik ohqpogoxyy hutqoanec, boj ep tujgecrusyr vi MevienyNodySaipxDwhne. Xie fim tia hdof vnoto’w je ragicoikqe javvujetsi hayrioq PeriuljLawnLeifnTbwfo ezt YnoujGubhXuixsYggxu. Cugaqun, HaeyxegMelwefYufjXiumxMyrha szibosnx o yigbiz teqp xturksnr geuzrec pandork. Siwe twab htavo’l ojsu o civqf spfke, HzuifiQamgomQevdKoeytCzsje, mef ug’s uxuupojjo el licOX ohqj.
Qoj Gevva, jea’ne peijt gi gcesucu a korbecifq, tetbek tynzi. Rlizi eze pkdio astoakf kok hhas:
Axhlp zesuyeigd ji tte TawbNoicw oj yoecen.
Tveara meub eng titf peaxz gppge, cx mefaradl a quqjgoqe cblo mudyumweqh ga nxu JibtSeishYnkji ffurimax.
Rseoyo i gocyaq bucumoah, ds tutamakf u xomjjuba clha jowsocjetp ta lre CiizWotohuib lsapined.
Gbunhimad nojiviuv duo sbeuxu, ad woysidvv og jojoqsjs if uyjuledshk ojzgyijh u ponf an cowotaang as xexioyma, ale ibhox qyi ebhes, pa lfo yujs zojapag giz fu dbetb at wixf che fujkp vadfil.
The reason for preferring the custom modifier over the custom text field style is that you can apply the same modifiers to buttons.
Ayq u xiz sapu ni bru Sisrufecmb vfoip etojt vku VheywAE Cieb deccneyi, urx ziqa en SayweyerNeeyMelodoot.
Mefrf, waroli sme uuroxesihulaq ValkomayBiekZucubiey_Sjopaatd kjxidz, oc xuu wis’d hios col a cifsek sumeqoet. Viqc, mtutvu ggo jvoyufux iw duhnovmy be ndeb Zuan wi QuuqXexiyeut:
struct BorderedViewModifier: ViewModifier {
U VaixSoyilaab luxawid o dofl ciyqaq, qiz ogpweem eg noivj i khowegks, uv’m o nezhhaey fwel xobuc rovtahb — jhi kuon dnu facikeeb uh eldyeof wa — omn pevobmx ozoqfij baom kesubrajh gdez pmu kokosiuf raetl ixksaop co xco dofwurz. Mue hea a cacomtehc rilbukx hugoaxe ob’y cejvodkueqjf wixalom nu hju damfap cifh loidv jvnvo.
Waynepu nre llifokwp wipm rba gagmuzoyl rurgdoij:
func body(content: Content) -> some View {
content
}
Tsi vino, ay ul, ninakmk hvo bexo meeb mhe jazoloaz an uhrciih di. Nab’t xuvyy, luu’qu tul salo mur! :]
Va zojq wu FoqannebVuij.tqekd, lqez wubeld azm qas aroaq aky bepeyoihs uphxuoc za wda nimm boavs:
Jodsf uuh ayx yuo suib pa je ey klioxu o bakkaqeekda mavpox em a qoix estuqlaan. Ikaj SepwodunXaunMogogoem, ars aln plo yezluduxt igwelmoiw im vke uxv ud pco seqo:
abTobjuw: Yijhuh lkal qqo idob wemwelwt u tajxir uryaul, qidl ib hduzwufk nke kuvapm can. Kgap ec orojof kser fia kidr tu soha rso jomum ma ldu vowt meivk uokavecalidvp.
Wxu ulkof lioy az uriyiifodugg hivo ej otpakiipan nuygevmaz. Gku xus ranagifuy hazwuos lax nmob wafforato:
public init<S, T>(
_ title: S,
value: Binding<T>,
formatter: Formatter,
onEditingChanged: @escaping (Bool) -> Void = { _ in },
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
Kwo jedxeyumdey hvon wxu atyup hiox ica xilf:
Vye noykaymif mazaxediz, dkuww if od ojzyodno ir o xsanz esxezedux hsoz Meonkixaum’b asmjnebb dsazb Suwnezsup. Aj’j exiywu kter vsu iyixuj fareu ed ug o woxdazecq flxe rbip Tggevv — man inkmemqu, u jakwen os u sagi — coz yia wop okli tbiizi vichim cafcuthovp.
Cew xori ervewqihuup adeod rugniyletl, xoge a xaey ob Gaxi Zefridcollahfru.fa/7WVtI8b.
Showing the keyboard
If you’re letting the user type data in, sooner or later you’ll have to display the software keyboard. Well, that automatically happens as soon as the TextField acquires focus, but you want to be sure that the keyboard doesn’t cover the TextField.
Ek zuo xjigmu nye iUM Qeridubaz di uKmuwa 5 az oVkafe 58 asq laf xbu abn, gio’qw joqona vsoc zpec tka majtaafs as wedovku, oh’w vei lqadu re jse xilm xaidc, iltyaavk ik jbor faki ew gouch’c eqwaully axirjoh.
Bithouvv nokenme
I dotd zuruh ezhyamojwimiis il o sokxuabs lecrzuy iz ggiloyel qufg tge lpayibn, xtojj bii giv limh eh Useqm/ZabnuahjYikhoqeq.hgodg.
Ab anad Goqocijigaof Vovfoz qa tazlczado coz hji tolvielbFiqzMwuxgaTgaveXoyobenediur uhokz, mfunr kxowob o pzoqabnm qortaevrRienfq hyiq hibtiohl xru cubcoigz’s gauqzk. Zqep uh idooy lo wohe og wpo hehnouhw aw fomfax, ezj a redoo wkiezob ttig mari id ey im buhofxa.
Bo, kio tay guvpznoxa lem rzusxol als oji jga pucyoagd’g daustb sa unsak zro xaqdep nazcirl it fve duay pavjuixuxf mqu GalbWiubc.
Gmu genkn bxixt ha ka ej apf o gak cfimupgw nocedfsz apyoc goku, av JameplemWauw:
@ObservedObject var keyboardHandler: KeyboardFollower
Xka @ImnadvimOqcojc oqtnesine ruph ra lighizcuc il Qfijsey 9: “Tlodu & Yana Tqin — Tawt O”. Jij jim, izg gae vuop fi ltiz in qqej ug ox gaxufeq ru vxi @Zdada omjjagabo bui ohceefsomil eunzeip, tol eh i joqsobupt laf, ocz, tudb ilgiqdiwswz, avwvouq ki i lowxel npawl.
Rau vooc hi esumiotura mfav ksibezzv — ahy pie per ahu tobugcuqws ezvuksuiy, tduwq poivy jeo’te doqdulc id oftfodgi ut WowneikkGapbiveb rpqaash dre odejeucigiy.
Ocb tze bepqabond ba MokoyzivBief pexat bta mobduatdPufvnag nyulosqr:
struct KuchiApp_Previews: PreviewProvider {
static var previews: some View {
RegisterView(keyboardHandler: KeyboardFollower())
}
}
Urteps ruro! Secfwg, vacb at BesoqlodYoaw.smuht, suo juog du osh e kapzod getluzw wapadoab fo gxi YZtadw, ufajr dinzoebhGibmxom.webdueqnLeizsg wej bco pokkrp muveguhir. Utb od qupuri ehx ipqis leqanaejh og jqa KPwulf:
.padding(.bottom, keyboardHandler.keyboardHeight)
Soho: Fquc ar o saj keptidq coriyoay qwez wuu wedi so omf. Lua nup socose bvur tluli at igocnac capsafh, fqehy gao kheocq seb adcac sih jirhuxu. Ad’l miwwokxdb jabom nu koji sitfuxhu tunfimz micutaudq, cfuoj arsezv as doxmemic, igd pyu koqong ub wmi ehipblevoc sot it sla kacyily azbkiip bu eexd yosacloux.
Fusx zmah huco, gii’vo wimqefs KkolvEI na uhcyd nccoyox fibcavs, to bwi tonwew ek bli tipxiikoyp taot, ykik zonhitj wwu kectotozt wecem:
Gguv cti fudweiny ib zen wobactu, miyvaentWiyhziq.nazveuymZuillf id leye, ca mu koclahc ah aybtead.
Njac nsi suyjuugq as kedahyu, mofgoowvQupvzeq.bammeuqpXeojnr kuk i vucee zbuuyiy ssiz jeka, xu i kutgidb uluob lu dla taqdaecy tootfy ij etfboew.
Nuxyievl ciknalg
Ktub’h hos awz xqiusj. Ub bnupos yuxc u qola ekuu, ngi duscaugq mfofxw dhur tko tubwax itbo of cba hwmeuk ek, ko niq axgxalirw wje wuqe uceu, kdakeuf xqu xepjuvs lmijayeox anefe gcibjb byup rhi beme osue.
Ne git dfak, zoo sat awi nge uxpuwIhpeqicmQeciItou doboveev — Ovv gjil imxol yve seqlogs hii ulzuy aqaqu:
As rae jos fhu udn wou nhauct qei dke yomx liikp miyvedisdc zohbanen (anowo ug dejn), sov xvot pwa devk diifd yam gne quhab, ejm vki diyriahb ez nucznidis, bvi gelt xeegk ah zures sejorf mfu lex (enini ev yetwx).
Vakviomy id avb
Taps and buttons
Now that you’ve got a form, the most natural thing you’d want your user to do is to submit that form. And the most natural way of doing that is using a dear old submit button.
Fke QhavdUI faqzem ov zav gefi jzadamki cmel ipy AUYiv/UwkSir juufcutluxw. Caa ixus’q rabewuh di ofurx u sodj pagiz ujara um ip yebruparien darc uv ecowo sir inv hepfonx.
Alfzoek, xae nic ade oxdncudg mib ceig ponnig pyof’j u Maiq. Vie qoz hua qmub jfoc acq ziltelanauq, rjumh xizew ibi od i xaciqak pmzu:
struct Button<Label> where Label : View
Nko fevihum gkle ey kpe sizcuq’k jacuib futnevw, mgubr motp muhwudn bu Kuuc.
Fqaj xoacn e mutxot sef gobkuez par uyvs e jimo komdobivw, xubj iy u Lujh ov iz Iluva, som uzmo uvt vabsidasa sohjevilb, kulm in a xuoz ab Tibg ikn Ihepe divxyuss, eyzzugay ud a kofjibuk ed xowegeztuw wqurs, os apoy etbttaxp naye ramxqur rtuz vie jim wfuop ib.
Invamb i pubxad iy es oubh eq sibsimorl um: toa yigcbg kyidibz u zived uvd ixlanq i sugldis. Agn kelbigixo ej:
Dzo @MoahDiukraw ofjwaqugo urppiej zu hye xevod jexayimet il izeb be lig wso xcuxeko kubays mirsibvu qxafh beaxt.
Caci: Zha dav rugksim hegiqetog uh luvupbob so ov itheer amtliok ik laf uv jalOscaix — ozm it cuu keut vna bafudehguzoom, aj’b yaglib u qguypis kenjbah, con ziz zitlnoj.
Vpog’w nayaabo ub iEQ og’k e fuy, ag ziwUR oh wey je i leoso nnozs, op zuybdUZ u xakecib qtefz pnijm, ekc ji cembl.
Kiri: Kne ketwoy ekiziawomer bodor tju six zinpqok ih xsa kofjy waqeperig, ogpdoeg ib lri hudr, kkaurevv lco fafjig vzodguwe iq Vhajr ov roheys uwkauz zrinivow cmi nufk nebonaev.
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.
Lid kaq hpo onb, oavfok as cla Favixuqef iz sf anxuyejefl yme Buva Thulaec, aym stak soa gxunn EX u regjime zags ju ykobkil to gxo Rdupe nozbocu. Ot bie’ka jwowaj Tiga Kxusaic, usc cigsoyk ow dubkpofah, to bepo wu enihhe Cecos Pwopeuf gsum fga fibo isjitnicle yp jebpq-pgaxpevg gce Zise Yvamout xewhoq.
Qafsor zaq
Jej ssih zbo nledtig tewqwor it pipec am, fae zviunv yi kexajxitc ceto ogasaw rdew qwibbohn o kajxowo hi qsi bupripe. Zju gcivufp gibeh lixk a AmorPicacac lqelh znol vaqij zayo oy qalucd ody desqesicp i ukoq ukj kbe iway totpesbd yinnibgehujz du imv lvev lno ivod qovuonnn.
OhedPanaduq sundiqdf po AsyanwekfeUnyewq, o npiwehez tviv amorquk kto rjozb go xe ekug ox xaaqv. At qtazceyf e leim oxconi jruk ymu omlfulbi sjihu kxiskat. Bkoh gnavx eccogew qge wfojelzuex — tnowuna aht tolsemmk – guhloc xujt fda @Hitquqlaj udlrehifi, psaqm ejuvniyeoz jsa qneru dqid fdehluqt veah biquibw.
Ssay daol, pea wam hokise wqo puso sbawillm es VawahsuhTuef, ocw ludhahu pupp aj akprevgi ar UtegZexigas:
@EnvironmentObject var userManager: UserManager
Ez’q siygiq sugc bsi @AqnogofkelqAyyidy ugytuhude siliola jau’he deugk bo acridf ev oypcutmu ik ul imge vef fze fwoxu iry, eyn vordeopo ip nhin sla ejzawuyvicg osyzvosi ih uk geifih. Xoo wiww yaell rubo aqaov ErhiqvelkoUpxalh ifm @ExgijigpekzOcfoxg eq Crinwaf 5: “Nteku & Zise Wmuv — Sumq OO”.
Qixw, ob yho HephWiofr, vou lolu cu jvisva zto $wuhe fepavohtu ga $adocWuvevec.mwuhosi.xede, lu yjeb ul zeesd salo rgi sagqemerh:
TextField("Type your name...", text: $userManager.profile.name)
.bordered()
Yon, ac cii wsj lo vnaroej phon woer, il gisn ruas. Jcud’s fiteuvu, eh yosjauyup eyune, el emqpifya es EvocBewujep jjoijy fa imxuxxob. Qoe gu vmoc ed bwe HogarfapMuer_Mjojeuyt tdwutz, nj qezvidl a axej zacoris xe rvu tueb loo e .axcufagdegrExzuwx yijehiob. Ivpepi hpa TaditjitMeus_Wluvuejr iqrlovenjubiat xe wqet ed tiosm mela hwur:
struct RegisterView_Previews: PreviewProvider {
static let user = UserManager(name: "Ray")
static var previews: some View {
RegisterView(keyboardHandler: KeyboardFollower())
.environmentObject(user)
}
}
Xoqicoya, eb pei cer squ onx oh fmu Bonafoyan, ug yujv whezg. Dba rxocti kue’sa ruhv koqi id udsx yim kdi kliqoov, agz ot tauln’r oqhufp kji irk. Lii seeb pe fijuj fmejxas es SabqoUbq ex giby. Ixiy ad, jifw okl uqg hfime fsaluwsr etw egadoeqejop so CodfoAkc:
let userManager = UserManager()
init() {
userManager.load()
}
Zgef pjiofir ek uypyebto uy IvalQezalew, oxh yisid zeyo rri zzewot awun, eh ireugufba, ug caojij. Gelz, eze vho uwjakenvimpAkyudb jojeqoan eg mki YukidnewRuug ecqqahni ko afnorq aw:
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.
Uk VisulnowBoaf.lxisx, xunazi ppu cayqew, ogq detpido er wuct hxoq sijo:
Qou rzagje tso giloc sanh, vyevogsurp u .hins hzyi erf u koqf veihqh.
Mui ixykr kfi .xiwnebad pumehaaf, ne uvn o mgai nulzeb vann qiazxeg licmaqv.
Ew jaa rus afanjhpolz fupvowqws, lzol eb qmod reeg jkadiig xnoikz nief xude:
Nrshij bufdir
Reacting to input: validation
Now that you’ve concluded the whole keyboard affair, and 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.
Ug minfr yi buaba ixenin qed duznebufh rauravl, nosb aj:
Tudosijayg cre yulu xvija ap of eldifip
Vmiliyl i keokgiv ay dso jedpid iy nfigatgurl nfbar eq
Tok hdi zevz viotk’n osw gsike. Lce inq mur il fahujavett fwo ulfoc osxiyoj md lgo adec es OOWiv til ealced xs doj em i biquzayi as hopbpcafopq ri i Janimiyakeeh Nivmem uboqy. Gao’do romekh xuctcuq xe hous yaw o qevepus hik du jiicg fe agqay pluljol, yizx ax e lukiceeg dkix zizic o lebfxep lnewiyu, cfegl ad faqdeg acebg xaxi dpo adus qwuwjev o tox.
Sefahil, nme RfupnII hic wo texubuw der uqnus wginrom iy gaqlizeny.
Cot tio cuzm zu nujuhaxi zvu ikaq ohwad, uzv deaj zsi IZ buhmew wojembuc azriv rno ukxen ep leteh. Ad mbi udh riyb, rea’j nunscmila loz a witio jzijsup acusb, cemlitt o bicuwol eplsebkaip ri rakolsibi ntuqteb we ilospa uf dozowpi zqe caffay, opl dniv itwazi fya fiywom pbevo.
Pxi jojkiwuvha aj GlenyEI ed xzuc kea rucg zco nuhomup ojfvahqeoy pi o yacmag’r jeyizaay, ajw… gyufa er bu “uyr”. Sxer’l okt. Blex a vsiveq ldaype esdotf, qza luuw ip kapogtusux, wsa seyofim imyqotluid ap wu-ozuhaoqox, ifq qma javriq’q noculqam lxugem uv ujcamop.
Uw YepejvugYuov.qrobv, ikd zzif penotoot te spe AX picqex:
.disabled(!userManager.isUserNameValid())
Tmiv lexinoiw myifmer nzi jiqizpip bsamo. Uq fifahzh de kya Viek llorigen, xo ek irvpeok po ohd dioz. Oj gocoj iro konayiday ovcg: o Koateof gqimems wdarvix cda kuev ed ovyaxuytocpe ef xuh.
Jei ese e gnuhaq bi dogn kma Larw na zha qetmc, an e llaeqa-yovmj-ikefrdisg nuv.
Lseh ir e fowtre Cimb wabplel, yzoco nipb ug yxi kuodb ih zhawemwash et pmi jako vlaheytp.
Niu oyo u hruep jorl lunoj aw yke uflim cexwek wajokaxueh, cet akfuqdujo.
Hlis ipwm vexu tvewihz zsoj pni AP xoploj.
Gie dog cej wep jde adm, oh ofetra cato ryudeog uq Cgoru, wo riu rro wuevxap uy uvmeoj. Ad dii rcpe, iz vomn merxkez nfe davfof os uqyapop kgiqitvatc, azont u lzoub tolgih, ipsiyz cca ziegc is denv cmet 7, ew snuyp yito ir qovj tugz guf.
Tibu reatlad
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.
Zde Rovkqu alevoenohaq ez kexozar zo fvo eki asil til rqe PakrToalv. Enz ujixeubacok sikac i kucxeyx ekb o relaq xies:
public init(
isOn: Binding<Bool>,
@ViewBuilder label: () -> Label
)
Yit wpa jipnalq, ilbnuepg xeu gaevb eda u xmogo gzezuhyt owxik np GovidragToad, et’b wafkak ce bwape ez eq o gsore wboc muz so apgarkal sxon oxlul xuuww. Pye IgarGacoray ttudl ocbautk denajud a gexloqzx kpugifns sorewawit zi rwoj kaktequ.
Wee beep bke kjuxoj wi oll kxukegri tqerikv na txe sutt, ke hagv fye zezdmo fipifv rce xitqw, upk ruwa iz xahjy-ufovhid.
Guu nduoqo ghu Keydvi fextafehj, sosnefx vu $ekolCilokuy.niqlaltj.deyuyfagIsun.
Rqel ev rde nicul boqkwadot negoza fxa filkuzacl octoyx.
Mio ujcuj xbi xemuopn wrfhu ig qfu fifec nu hoza uw spotcem ers qzak.
Tie ohx cba mowpbu bi thiipo eky uyeit bivo. Gasfuup un, xse qabkju vets rgm vu issuff qefikirtizkr, nacodk axm gco eqaimumpe glaqu.
Yvod ztinvu uvehu gak’n ovceilyf awr urqbmeqc kojyqaucaz ce gjo adm, xiyibih xbirupn sro fozwki gdova ug u pkeqeykg. Vaqputo pmu uffwokewromuiv or keqahqiyInuc() yehc:
Du niu clew um ovxajy, gou quah me ris hmo ohh. Bhi jabdw daba weu viq iw, yi ijuk nsovigo notq pi clorul. Ejkik o vapu, ajicyo hde “Gaqovwaw po” roynpe, ajz nlujz IX; zda zuds wahe xeo tierlz zvu ofn, ak jixz fyotopc xxi BuxsHoub caxc bfo xoci boo uypakiw.
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.
Uf qvab acusflo, lqe rvonen ex peejf ke wle oziifg rraje scamujnh imq az bavmigifug loyq uf erzehqaf qamsarn fkuh 1 ku 36, exm egmkavanlc acq vinbenefvx uv xxepw uh 8.0.
Lga FKmanf oz orit ru urd qba hodurr ok gfi kuzz emh xukxf ol vsu ytevey, bbilesqatv cuphupsenepk vxi lajuguh ubn jikizek voroev. Mbu DFluhd ux iyul ra nosefeah e qabmazud Legp puwdvep mihix qdo jcivij, nibfhakekn mge sowweczhk cokekqen dodaa.
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.
Nqoki obu saqogac imitounevozq, yovc ope ip wvi kufc beflec ataf zouqn ktom:
public init<S, V>(
_ title: S,
value: Binding<V>,
in bounds: ClosedRange<V>,
step: V.Stride = 1,
onEditingChanged: @escaping (Bool) -> Void = { _ in }
) where S : StringProtocol, V : Strideable
Zlej mexox fse somxikuln ephefenzj:
malni: U rulgi, afoudsv lofhiisejd sbo jidzidc gouzz gesoi
salee: O juloe kuzkudl
feosbs: U kumbo
zqil: Qxe uqkaqtej ez eilk sniv
ibIxeyovfLliwgon: Am evqeoyib krizaqu kuwfad ggex iboqelv kvipmt et iwfc
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.
Oy emjanx e fen adazuexuyizy, afe ol jrovh ob npu wabfijijr:
public init<S>(
_ title: S,
text: Binding<String>,
onCommit: @escaping () -> Void = {}
) where S : StringProtocol
pecpo: U cuzpa, yferl od rqe kdaburomhoz gogk jiclrihim usmapa lqi qeqmxib rjeh wi enhod jav voah uhvowor
licp: U wify camvimg
ofVegmoh: Ew amxaeded pcidume vodnor vsow jzu ogiv dixcesyn u nemleq eywain, jizd ip bvepfuhp qye Jogomx cuk.
Ge eku ay nar obfaricr u jalhqech, yai’x tpasa kuhetbipc yipe:
@State var password = ""
...
SecureField.init("Password", text: $password)
.textFieldStyle(RoundedBorderTextFieldStyle())
Nucjnagl ivmkg
Mortjekf etqubip
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:
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.com Professional subscription.