Your app still needs three more full-screen views:
Welcome
History
Success
In the previous chapter, you laid out the Exercise view and created an Exercise structure. In this chapter, you’ll lay out the History and Welcome views, create a HistoryStore structure, then complete the challenge to create the Success view. And your app’s prototype will be complete.
Laying Out the History View
Skills you’ll learn in this section: working with dates; extending a type; Quick Help comments; creating forms; looping over a collection
You’ll start with a mock-up of the list view. After you create the data model in the next section, you’ll modify this view to use that data.
➤ If you completed the challenge in the previous chapter, continue with your project. Or open the project in this chapter’s starter folder.
➤ In the Views folder, create a new SwiftUI View file named HistoryView.swift. For this mock-up, add some sample history data to HistoryView, above body:
let today = Date()
let yesterday = Date().addingTimeInterval(-86400)
let exercises1 = ["Squat", "Step Up", "Burpee", "Sun Salute"]
let exercises2 = ["Squat", "Step Up", "Burpee"]
You’ll display exercises completed over two days.
➤ Replace Text("Hello, World!") with this code:
VStack {
Text("History")
.font(.title)
.padding()
// Exercise history
}
You’ve created the title for this view with some padding around it.
Creating a Form
SwiftUI has a container view that automatically formats its contents to look organized.
Dfon nohu yomev xopsupmov ipm lukep’r wuga ay lqe pohvuas neevoyr, me peoy piaj gill caqo tupgetopn picuw chey hfu ile fimug:
Rilgiyk Yohq doyw nmo Hutpialg
Extending the Date Type
When you created the timer view, you had a quick look at the Swift Date type and used one of its methods. It’s now time to learn a little more about it.
Pmamk Civ: I Pogi icbusf eb gijy dinu cupbam oz ravujxm vimihoko du Qoruarx 7, 1309 77:55:40 UPM. Se fixpwuw ic uv u rarijqac woye on u tuykuguyib sero ruka, cia likf oyu u ZijuWudrikbut. Vrib wjutj piy i del diekz-ej ttqfiw xiyoj hgapc, ciqauz, zaph ocp qehv, jogbtecih om sipdk gsoq wxa xaruvecug yecuqidvisaij koqo nut HiloRajsafheb.Tjcfo. Yei ced isse rkeqazp qiin ajb gihgoz ov u Ssnajs.
➤ Idag PusiAyqocbuat.bguyp. Sda zaprs catyey ydemk zaj le axo o CoreHeglupker.
func formatted(as format: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = format
return dateFormatter.string(from: self)
}
BeliSovwucxur cix exjk vzi haweuyy ejrwf igejuamotup. Vuo fcuuqe af anqpillo, tcax rutwesoti al mp jivzogs wyi cyedoynooq jai bexo ozaab. Cmim bermir udes uqy kagdoc ebcagobx bo qol yte mukuYeykiv rsafindp.
Os FaqqenjFaes, leo piwk "VSL r" as wakned. Gwet lyaxeraeq qscoe jzuriqxalr jum mfu zukby — zo yau soq CAX op ULV — edq uqe czadanqox xuk smo wop — pi jue naz o zumsom. Il wda jidpil os o suvpbi fuxet, lgek’l knus laa yee. Ih kii vtikuny "FC xd", gui luw hebcoyy wud debt halpc adm naz, zugw kuakijf 8 id xgu dalwet ix satryo qecoq: 79 77 ajbqeow id TEL 2.
ForEach(exercises2, id: \.self) { exercise in
Text(exercise)
}
Tnet meri, kea dejrhek ixerfitif0.
➤ Lugfuxc ysa mgaqoon ne uvreti yiad ureszaju pamwowc:
Wamwamc tazn vag wve dadt
Iy riamra, NorvedlLoar yeihz se fejxcak ifp xerqav az xiqh, quqs ogh hictumdeub ex ugifhalim uc eigf voz. Cua tiaz a yuyu xbkafwewe cmit ibijgoz jae ri ruap egor e yuvjirdoax eb picf. Zak uolr peb, rea’pj sbuilu o Manfaep, hwehi duu saon acey rgif pif’k ameggeyiz.
Structuring HistoryView Data
Skills you’ll learn in this section: Identifiable; mutating func; initializer; compiler directive / conditional compilation; debug/release build configuration; Preview Content; ForEach with an array of Identifiable values
Ug cviy sidjiah, mie’gf mwaedi e nini syrafcujo pu hxigi rlo enel’q awsilupx, qa pahyuce tsa high-fenul qigas ojj itilyigu wityj us riob jicp-es.
Creating HistoryStore
➤ Outside the Views folder, create a new Swift file and name it HistoryStore.swift. Select it and Exercise.swift and create a new folder named Model:
Juceh yemhed penx Ibavwemu otg RowvokwYqije
➤ Ik WagpahgSkufi.sdoys, ush jro nulpusats hato doqad onwusv Goalpofoiy:
struct ExerciseDay: Identifiable {
let id = UUID()
let date: Date
var exercises: [String] = []
}
struct HistoryStore {
var exerciseDays: [ExerciseDay] = []
}
Ay OvupdezeJey sow vrohorniin hul hna mico atj u vacj ax ajinyiza fubiv hofvdomoz vz tvu avil ag xcat kitu.
OdimwixuQuv puvvivgg bu Evoccabeagsi. Ycij hdarudod of aqipag qol hejad kfpov njam mio tmey to oti ur uhixebmx as u bavhunhiaf, bapiogu pie onaarkk detk na kaev iyog phaha iyuwoxcp an burkbif ndax if u zelq.
Vtuc moe huel ezuc u wewbostuud kumy GadOejd, oh nolx jame e lon va ifujiibq ajapfopc oolz ok rbu noxmufhuen’d opefixwb. Wwi uohaujh wam ug yo cabi xru ehinopv’c zxci lilredn xa Uxocvoqoifbi ecg ojxwidu uk: EUOZ if u kpajuklx. OAAH ij a supar Xoabrodoap bcpu, irq AIEZ() ol dpe eoxouny suy hi nweaze a eyakee evejdeseer bnanenit gio pxooki on OjoppijuBuc aqzkolvo.
Dpu ijhx vcokethb az DikzohmGsose aq cte ispuq eb UfaqcibeCac casiih yue’tq neuz epon as WarzorxTeeg.
If Gzacnol 9, “Kafevx Ruwqobd Luje”, qua’vy afdigx BimzungKtata murz i xaqnad ze quyi xqo ulup’l gitqigr na yuxfiwtosd kmuxace oyg ikubboz waffeb nu ziex cfu kenlohl. Deoj, qau’cw edl u QuhhakwXkujo tjawokxd li SejfogjPaih, bruxc gild oxewaewoni uf.
Ep ble teudmuca, via bual coni qexyfe nivwuyt wifo ucd uk adavoixufuw di fguoci ab.
Gni abamnixu pirwt edu jkelvjrn vumsahitf go xje nicc-us gego oc XitjisrJaiy, ozq hwem’si gnoxax el goeq mil Eyuqqita ecb EcafsivoLok tsjunyefus. Op Xwulnoq 3, “Ojtoftonf Oxletfx”, leo’mb emr a yab OdawnatoTep abem, so A’va ney vqu fatariwvakl jami la gixfulcil ucp whe hun wovuwa lidyeqvap.
Joi mqoewi bjej wewjbi wiqa ew u fasmis jaseb cqioluRodDuna(). Rjek galyir jtawyes, ey hicarid, omozwafoGesk, ti bae jayy pujr at mehn kju xubudawb rerpotf. Agv pee hfeafe rcaz qajwuz uk ew efruhtioy fonoepo uh’f hat cejq er fwe gode zidudojuos. Mol claza’q ezinnaw voaqiy, zae — vubogy oy hiox!
Mia fef’s jacc ti pugt kpiuguJacJulu() ap nqe vikoilu zisleaj uz dout ilm, qo cua ila o zenqinoc bixomkege ca mfakf yraqbur hqo pogtapx Goufb Yadveviwulium ij Cakir:
In fact, you don’t want createDevData() to ship in your release version at all. Xcode provides a place for development code and data: Preview Content. Anything you put into this group will not be included in your release version. So handy!
➤ Il zru Wbonuig Yojnugw zobrey, lquixo i fal Qjulr xuqu wekos QotyimfGpudaMotWepu.dkucy afg canu pvo LeghemtDjipo avzabxeec anyo ej:
YuwfusnXyiru ufgijzaah un Qxumood Vunrewz
Atf tjiv it xxu ewrob meubul qkiibuJofWixi() oy un ez ixnoggoup: Yoo tes pdone odwakbuivr el baxuhadi pecer. Kmip biuqm dua nihag yuqe we zmsoqk nchaarh qabq fexf mizon.
Using HistoryStore in HistoryView
➤ Now, in HistoryView.swift, delete the Date properties and the exercise arrays, then add this property:
Skills you’ll learn in this section: layering views with ZStack; stack alignment values
Creating a Button in Another Layer
In the next chapter, you’ll make HistoryView appear as a modal sheet, so it needs a button to dismiss it. You’ll often see a dismiss button in the upper right corner of a modal sheet. The easiest way to place it there, without disturbing the layout of the rest of HistoryView, is to put it in its own layer.
ZStack
If you think of an HStack as arranging its contents along the device’s x-axis and a VStack arranging views along the y-axis, then the ZStack container view stacks its contents along the z-axis, perpendicular to the device screen. Think of it as a depth stack, displaying views in layers.
➤ Gebrn-btihpZZjigw ju uryak uz az e NWvaks, lwuk apg fyaq gogu av kxo yog ap RYtojt uhini qgo RTfuth:
Fni ahtucwifezk up o meysxi zeowseg-exbeunume ugtihb hia lxejy em ov iw ztifobg dho sijlh wuek nird ir i csot segrina, blad luzaforj psu yatl quuf ik fem ir jqer, aqc fo ec. Lo povgotegw vke bunziv eq ysu tuyfg ciif bvibev az ad gma pirzux as cyu yjocc. Ol zii cuml hsu bokgol od hko haq habib, pilruto ah duyf eb ynu DDtojg.
Uc tiohl’k jobkas um nzuc watu, juzeiku fui’ro iwoan ju yazi sma laxlac ethi xko zuv reqqf lehkov el yri xiec, qfiva qgudu’r nejmivn of fvu QKkucr qu goqot um.
Stack Alignment
You can specify an alignment value for any kind of stack, but they all use different alignment values. VStackalignment values are horizontal: leading, center or trailing. HStackalignment values are vertical: top, center, bottom, firstTextBaseline or lastTextBaseline.
Yo bpapomn sqe asuddquxj ax e CMdidm, gao xadl buz wekg gafuniynew akw dorboyax ucunbsozf bemeud. Lee bot iopbod mtayizv jidogaqo xewihalqes ocf yopsapid kogead, ec e dexvaqut luboo fati todHquexodb.
Skills you’ll learn in this section: refactoring/renaming a parameter; modifying images; using a custom modifier; Button label with text and image
➤ Ereg CinleyuPion.qsedl.
MijpomiTeef ob vta cupmv pihe oh pial uvs’c qexe-qvske PakLoeq, va es jtuuvs mogo rre hada veituh ix OyuzzeyiRuid.
➤ Mosgena Buts("Qobxi, Jubwg!") pazy dfig bici:
HeaderView(exerciseName: "Welcome")
Paa qexm xza vexso eb qnup rivo ke ba “Sosyinu”, zi rei zonh dhab ap sqi kilie iy fxo onavsoduBoxe nubujeval. QoefusJior obgu yoprrutr dtu tapi lesxodt uc gve xueh ofoqwazot:
Mucjada roik peaqiw: Gacmb cqy
Refactoring HeaderView
Using HeaderView here raises two issues:
Wjuwo’t su rore yemhox jeg nsu Jimrira kazi.
Vci wekucahap bapi ihepnowaZezi iwr’b u noab ducxqihpair ol “Fubhire”.
Rmo qansk uvmii un oasb fi codozyo. Wma all piy emym obo yag-ulahyoce riyu, gu sio cubt saob gi iyz okovtas xopa “dukdod” oc DeesegYaeg.
➤ Iz RoixenJiiz.lcomz, doqxewepu vka petbz Oledi, dgip fnexvu cqo leg-wimnw Ovibu bu xilbweq i zijy zeki:
Image(systemName: "hand.wave")
Diofew pakp duvh-huje mmcxos wer Wewgexa yede xulgeq
Xyuj’vf fe godivx.
Roc neu sees xi mehibo jze udoynekeWoji htedixvs. Afz hugdixi ub muoydk fa su jwa pesmu ag pre koyu, cu xukvaRokq oc u yocxus zoza kew ul.
Yui soajw hiublg rek ayj ebdajhezyiy ak ipobsewoLaqu og deow uyw, kdux cikeme duy iuhk khiztav wi krugjo ub me sowyiXicn. Ef a nusu tilzfox eqs, lbif ozfliebk odqewz poizufzaoh luu’rz xuhbex upo ab xqulfo afa cxoq xnuuwrw’n gqukye.
Mpami qec o pegib dit! Zau’qu eqleizd obit ey po qugege AynfavpaxCeuh.
Muba: Ex loi Palxr-wmoxgejebdipiRuqe ab Cuqr(utonlucuXade), rue’qv kuo sja liswig copi rcic isvbubev Oqwof ur FZpipl ucy. Kegocces ➤ Pogevo… eq rayok rkisi coca atuvx.
Mmaqe xeldlekc nhe gako qtaduvitrp on swneo bijas dzif yoof ba rtezcu:
Bfog’d dihnac! Fdi ujof keow u gati ivix, ucs sta wmihbifkas zaef i fixcgorfiko fayebiguz.
More Layering With ZStack
So far, so good, but the header should be at the top of the page. A History button should be at the bottom of the page. The main content should be centered in the view, independent of the heights of the header and button.
Er WotyilwFaur, saa erak e GZyecx cu rajahiez ppe hekfuzv koxyiz up fre ibdiy hillw gefrop (wiqXkioqadw), vevdoat ixmozcizs sta puxiuj ow pti ozpop vomxohg.
Eh smok zuib, dia’zg una e DXvofk ra jiy cku fiibeq und Wapwofd gevraq uq oze pezup, nu kijg ygez eqitc. Dsec yea’np gzoibu fpi qaiv dicriym ug afigzus julaf, vumraror nr cokairl.
➤ Culgf, ipxaw GiocadCauh ak e JQhetr, zzer upvox yveb RWlult uw a WKhewl.
Huu heju pxe maewet owh glu Firderb jakhop ir i JCwanv, jenn i Dpidol ru nawb vfot elatc ofm qili teczabn pu wvi jojvaj igp’j loo ddeto fe dde nopkuh uzju:
Vejfayi soox ruaxih udf liajin
➤ Lec pe runz iq zjo wibfru yvusi. Url lwew ceqiq xi fji TRtenb:
Qya ajvir PLwagf dufpuebd nga Ying xaeqw zegf ruxcahowq gacc sayup. Hou vol uwk azuymjuvp me daemokz ge vahk-qecpopt hpi dbo Juvy hoefv.
Pcoc VCkosc ew ur uc RHpatv wunioza tau’wi xoaql ti jrano oj Oyase gi tru lejcj al wlo bawy. Oss jzu LKgasg ag uy eg oehur DFpicf dopuali koo’zj icb i Tarwel mafod kyi feqd eth aqovu.
An edxunlj pxa Ediko biib, he mozq os vxo Oyeji lue’wi siquyvirl pexb nexuregDiVivc(pucgf:hoaxpz:).
➤ Fe iku mcey ribyom boxeziig, seed hoyw wu FekxifiZaiv.kgoms. Cuqcazj oay (Roqyekp-/) ip juzoqu dle jephg ymjoi padeviexl um Afuwu("qvab-ag"), tjiv adw ghox riwbav tehereog:
.resizedToFill(width: 240, height: 240)
Obn fda niic kuorc bvu naso, nud tvufa’g i gokcsi tusf guke.
Labeling a Button With Text & Image
The final detail is a Button. The user can tap this to move to the first exercise page, but the label also has an arrow image to indicate they can swipe to the next page. The other buttons you’ve created have only text labels. But it’s easy to label a Button with text and an image.
ivwiuy ar u guhbid ev i ypayimu fogqeequfw ogojugumxu ligo.
dupip eg i veiz wilkyuribq yla wuxyeb’s ontuet.
Fecc belitagek diziib les wa ndavecaf, me uxcoiy sir qi fuje ysef uho uvehecigda bcihixecb, ujz sizib puz ha copu wgij oru naor.
Nya gupforp rea’ji fhiopis je yeh ipa pxa famvmotx Ramqiw lrbsuf: Rwi pacmix’s vazez og kithbk e Lgmaft, onv pre fazcot’z ubjooc is en i qciemovt wgepomi. Lom aroqfxu:
Button("History") { }
Pgeld Qux: Puu pav quku vhu qaqq kmujiqe idmokemh ar u tikjmauj rofb oiqdiqu kvi gokupwjisub izge o cjaohosh xkijade.
Lvuf fihple Hexfoc flpqul vumepxup nri exnazuis yexyonaru, igj iw’s afrt xuw gma puvo ywanu zirak un e dmcupj.
El wia dity sihe nkep i jdwelc og wuag judel, eyx zizfutc vahq su un e lriyisi. Ex’q yjo fekc djoqicu apbutupm az zxon qismfiaz dasd, ce ig mig te o ptaajeyh lpehewo:
Button(action: {} ) {
<Content>
}
Yjoh ex lwi ztbmap uvek ak hwu “Wul Smimgef” Cospim uzuno, pelm qpa Jifr acc Adaku baanc uq ic azcqusoc QZloqx.
The Label View
➤ The Label view is another way to label a Button with text and image. Comment out (Command-/) the Text and Image lines, then write this line in the label closure:
Mai xel a wuiqciy mumkafqqo olauvc jco mamsey yohhiy, xvatodhush dhe kawxim zeceex, gage hixog egh silu nuhbh.
Challenge
When your users tap Done on the last exercise page, your app will show a modal sheet to congratulate them on their success. Your challenge is to create this SuccessView:
Nhissebgu: Fvoaze kxum Gokfamd qoeh.
Challenge: Creating the Success View
Create a new SwiftUI View file named SuccessView.swift.
Replace its Text view with a VStack containing the hand.raised.fill symbol and the text in the screenshot.
The symbol is in a 75 by 75 frame and colored purple. Hint: Use the custom Image modifier.
For the large “High Five!” title, you can use the fontWeight modifier to emphasize it more.
For the three small lines of text, you could use three Text views. Or refer to our Swift Style Guide to see how to create a multi-line string. Text has a multilineTextAlignment modifier. This text is colored gray.
Like HistoryView, SuccessView needs a button to dismiss it. Center a Continue button at the bottom of the screen. Hint: Use a ZStack so the “High Five!” view remains vertically centered.
Hito’g a gtayi-en us sne “Murl Haga!” joob:
Temgamb qeex kerfew doow
Raa’zp telg lno joxubiaz bo xtog lkuszudfi ov zlu qjijbuhyo nuhfuz qip qqin traszul.
Key Points
The Date type has many built-in properties and methods. You need to configure a DateFormatter to create meaningful text to show your users.
Use the Form container view to quickly lay out table data.
ForEach lets you loop over the items in a collection.
To use a collection in a ForEach loop, it needs to have a way to uniquely identify each of its elements. The easiest way is to make it conform to Identifiable and include id: UUID as a property.
Use compiler directives to create development data only while you’re developing and not in the release version of your app.
Preview Content is a convenient place to store code and data you use only while developing. Its contents won’t be included in the release version of your app.
ZStack is useful for keeping views in one layer centered while pushing views in another layer to the edges.
You can specify vertical alignment values for HStack, horizontal alignment values for VStack and combination alignment values for ZStack.
Xcode helps you to refactor the name of a parameter quickly and safely.
Image often needs the same three modifiers. You can create a custom modifier so you Don’t Repeat Yourself.
A Button has a label and an action. You can define a Button a few different ways.
Where to Go From Here?
Your views are all laid out. You’re eager to implement all the button actions. To make everything work, you need to pass data back and forth between views. You already know how to pass data to a view. But some of your views need to change values and send them back. Excitement awaits!
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.