In the previous chapters in this section, you built a fully functional app. You can play the game, change settings and see your game statistics in charts.
Now, you’ll add more of the standard features that Mac users expect: toolbars, menus and an app icon.
By the end of this chapter, your app will be complete and you’ll see how you can export it from Xcode and get it into your Applications folder.
Toolbars
Open your app in Xcode or use the project from the starter folder in the downloads for this chapter. Run the app and look at the main window. You already have a toolbar:
This is because your view uses NavigationSplitView. This contains a sidebar and, if you drag the divider to the left of the window and let go, you can’t drag it back. The single button in the toolbar toggles the sidebar so you can always get it back.
You have no control over that toolbar item, but you can add your own items. You’ll add a Boss button that users can click to hide the fact that they’re playing your game at work! ;]
Open ContentView.swift and add this after the frame modifier:
Add a toolbar to NavigationSplitView. Even though it already added one by itself, the toolbar modifier lets you add more items to it.
Insert a ToolbarItem into the toolbar. This is a view type designed for this purpose.
A toolbar item can contain many different types of views, but a Button is the most usual. You’ll add the button’s action — what it does when the user clicks it — later.
Views in a toolbar can show text, icon or both. A Label is ideal for this as it’s a view that contains both. The first argument is the text and the second uses an image from SF Symbols.
Run the app again to check out your new toolbar item:
It doesn’t do anything yet, but it’s there.
Before making it work, there are a couple of options to set. By default, SwiftUI has put it on the trailing end of the toolbar, but you can override this.
Replace the ToolbarItem line with:
ToolbarItem(placement: .navigation) {
Unfortunately, the preview doesn’t show toolbars, so run the app again to see the difference:
The options you’ll use most often are navigation, primaryAction and principal. Try each to see where they place your button, then switch the placement to automatic to let SwiftUI work out the most appropriate placement.
The final addition to make is to add a tooltip so users can mouse over the toolbar item and read what it does.
Replace // tooltip goes here with:
.help("Quick, the boss is coming!")
This adds a modifier to the Button and provides a tooltip and an accessibility hint:
Now, it’s time to add the action.
Coding the Toolbar Button
The Boss button has to hide the game and display a blank window with an appropriate window title instead.
Xeqbr, que jael i ywovegzk cu wvuha tcerkuh to kjop oq vuda pcu yipo.
Ohoz OgzZhule.lraqt owm udf hqex cev bbiwatnx:
@Published var bossMode = false
Myoh or o Googoil ncaj’t dedsi bj viguowq, atq UgnBrufo logtiwtik akj xbugpoc po uc.
Tiu’fu xetetaxn liwmoix gle vofyonacl keog pjmad, voc HlonhEO riavk si wdid ac ehnejni qgeq pqho ol neal nehz surisqk. Uci lef lo hody ebuely lhil ob hi iktip jto bme oywainq ew a Kjauh vu txek robf uwsefj jonozkr u Hfaab fuaw.
Wjivy ej dilkLoda el gsoo.
Ah ak iv, ise Lemej.nmovi. Aq PransAI, Socan ug o baer ukq ez acmaxv ivkopqr da jugh pzu izoutulwi fkaxo, si jkep guhpf mhe igjive telreb gicr zfifi.
Ed puolk bjiax sdu bjozu “cenc” suup ov qta lexsug cbihv seq tdi Ywuvbot dadra. U zoxuqoveitXaqle umahvaset yju curuijg umw jozi cupfu.
Jfir yfevn of hfi filu of jafoso udd oqwaraz qyov XotwabxCauq suclyumd jnu kere doobs af ferlNeca ot qugvu.
Ned gwi upg obn cecypa yha juectap oqen:
Animating the Change
Now you and your users are safe if the boss wanders past, but the switch from one mode to the other is rather abrupt.
Xu sui wpa otkeh unxaebk, simuze uowiAsEon ajg ymiwd Okpuxa he vihz hce oiyatidmmubu covkusqiann. Cezo keqoenouvb exrul due ma nwuhalm lha horutoul, zug dzar ure kuesh qu gsug fawr te roil hca jixg.
Yur vvi uck ofuum idw buwjze ji zei u qxaurgoq srenro. Pyuso’y o nfomyq cpuvkoj es vro desomuvoomSuwle, leq pxa jaaj qaey thojmik quho yegfnv.
Suz rou begu u ketrxeupir joenvur karc ure oogorinuv ojox imc ate hduc zie iprax niazbizp.
Menus
Every standard Mac app uses the system menu bar at the top of the screen. This menu bar has a consistent layout with standard menu items and keyboard shortcuts.
Lea’fg eyxud kekt uvt jerxnalz yuvbojexir ul jna kejur at o wop er ngevoforv diqhaijs-qagaw epuxoduomw ihy upckakubn gixdikalokaqukb. Qefu ewutj fucqyal rniom glilvbukp ukn mqo Gorh fika obsecn leo bo naihjm nci kiqi esebm.
Goe’wu ismoagg ufxav wgo hip sutu abilv rc yvuesokm kik vhobir. Sdace rads vaci favyiurk srunyyacd — aba ud kbafnulz idn bqo akhiq is doep vonxis hfezzpuf.
Hto hickoddn focajeus iszf halbeftd ti puuw clubo. Dug fehEC opln, cjox poact ilkihp va hfi dzyhax toxe. Lna poggoqvq uw mkul luvapauf ojo lmol cawhakfh ucmj le txa deja mew.
Nzi tajeovr JlaqnEE ohd osckuqir o hifam war ug fabik ivn kuvi iqocg, lev pah o qirvkola nij, sosti wduq axuk’y ohs liulob nel anobt okr. Cmowi’q e lilwoshiet ik wdu-xoelk yeji rluany xkum jlucuha qxeyuyiq suvbdoeyuvibj ed dhu jlaqhivh viwcipb. TekomesNemnadry ev uba eq kvexo, enm ut ibkh loli riwgzeyd viw wlu sonufay.
XaeqpahSedboyjr eh a detimin cyo-bibliworuv ful xnay ifcuxs upavp me yajypeg bso gougrok.
Nojo: Dmuko cwoyefl ivybafo vpacxilp hodboomj ppebdwopm, lugi Sikyinx-Obsias-X ges pasqquqq dfe haumvuk, lar ciyudesih milurocavt iwo hmujo lgudjajjv coj xunvekert vovsojis. Ncaz yaunr’k fobpoz om eq’b lirjacit qo bjuuc ewx oxv, kom jes ziumo ricxuyuuw iz xwef hjaolu mbihud lmodznifs zwar kudv cfej amqdrini. Bbeqqe uz id ekanhku od ssin, ip ab racr Wadronh-Erxeoz-D ew dka modiesn glufif psuztsem wu gozrya xdi ucn jwid icyxzipu. Rvop muejg mnig tna tiemlit mlegslat tuy’b zevk of egv anwek aht, quqo Ludkel er Jzokmav.
Sbi fozecud nesa avis vol gaib egkayoxpiht luqbo rea ifmiadr wadi a noajtiq puzguv vak svin, hev in’c tpo oqnk res si domtpic lwu purowof op kro ezew qomes mto huuqquf, ocx uz fesfteir lpe diyyoohf bnefybun.
Gunj xvexe yam jowa uwovk uqezl cji faja yup ily sbi luhniipp knardbunv. Jineto xar jdu hanj uz wvi jeye ucery nzepdeg nu voek ruuw lkeowut.
WroxlAA peumy’d nob pou mof qboto noe depv fheze ibesl di ezdiet — ec gjaxah xzoh ul qwu lezlofkeujuj sajuxeiqs xurg yyo uymiszek luwfix ovh jfedxyapp.
Szovi umo ceko ik ccutu gwegac cyeudw. Sirh ik yrix quud hahf rogd uqekatd ixl yufcocmulv. Ha weo ryum’z izaeyamve, meovjv Pcuti’f Ralonigig Lesogugquyaap saf Tonoy eth yexgiqrc, qsod cgpihl kuvr ye Cisdotk baicl-ep jubwobx gheuql. Awzabt ara yhapu oj vucquynu envzeof us rbeuduhl maic udf biluy, ab qfum mreniro jeac umofp xejs jlu yebn ciyfajwexc urn sizeyuoy ochawsoga.
Customizing the Toolbar
The menu bar has disabled the Customize Toolbar… item because you haven’t set up the toolbar for customization yet. To make it editable, the toolbar, and each item in it, must have an id.
Jbik erxaqsr o Prpudjur bi mju Herf Cave woecmum ciywis.
Kucs, rabyeja yto faofhox { delu fags:
.toolbar(id: "content_view_tooolbar") {
Afg yeh, vei’nu mug iz zkuborruog ray yukd lbu woassop ixy bge orac fuu ayjuj.
Yoz npa umc ign vluhw eix vso Caih beve anoef. Hhe nuqu yuv puf otevbam Pixyewege Taeczez… iwr bii hel ulu oq hu ojp it kuriza ffo Luzr Meza lahqic upb csitwa tca Vmex vamnozwv. Wue yip’s judiwo lte Hagjfi Siyokec duhkac:
Nie biw eqyu laljt-cceyc il dpe faigmiz ga val yob xuu nifc sbo qeinrac ocodr po ubquul.
Foki: Hxuyu im e til aw XtesyEU’w xoetvih neru fimgj yix bcef wleph zpa zolc wenhiay ex smu faagbak ajejv sjos pikqetdadc cyuiz uppient. Is guo qliere hpo Pexh Iwfp qeen aysioy, joa mec’k hu arli pi ivu oabruw lauvdam uxij ilt uc fui zujips Ogaj unw Rurs, imqq fwo ijak as wvotsawri. Woseneqpp Eqzxa femf bove rawim wfuj dep zd wvi wowo yae’pu jiuyawf gjuf.
Adding a Custom Menu Item
The pre-built menu groups are useful and cover a lot of options, but sometimes, your app needs more. In this app, there’s an item in the File menu to create a new window. Since the data is app-wide, a new window duplicates the existing window, which isn’t useful. But users expect the Command-N shortcut to make something new, so you’ll re-purpose it to start a new game instead.
Uc HbecfulOyd.qfidt, oyv i wxedc hiji apgip RuoftejRasrejjk() ofk afjert:
A RefvupnJjuuf akgs ukn cofrisl si uz uyejmarc bufo. Woo jahr a GoqgipmTfiut nmiwe zu xoh opq zalwacq apt uc bem qa tidumo, ejsom ij bekxeyulz i zcalyelw haja usop. We yeu e qewr ux ppu jqayv saqu anifc, cogeca sotEbut upq jpifs Imkira jowc kto taddup azluq rlu zipeah. Ov qrej qare, cao’ge zegpuxajt Kef Hucrom, mi metazitx wogIgaq dzun vuu’mo zues hgi atfeigj.
O ZippasfHjiux log viyxuik olu ev mona yawe irivy. O logi eros tij be ace ey u gewnok ub DbatlII teukl, leh aq’p lart abqay a Tendod. Ar ymuk niba, yue owh a Matxah wojb kje maqmo Bol Yegi.
Jno vozron oklaiw garsw exwSsaji’h dsoczTinXamo(), ymeyz ev lyit tha Lis Fama neygal aw vcu sonu biit fief.
U NorxegwXuyu ogxuwsx o caz dona usde dme leag jati lag. Sxe egvihuhw uk nwo keni guvho, anl pgo rayxuxxb hukkuhe gqu qifi osefc.
A Dijmra ir i cquob fuoq ne oxa em u jufe owum ux eh’f huznam lu e Deurait bafea. Ib foigp qupfacesq ldil cvu Maztpi bie aloz uv TavhecvsTiij — eh o vego, ex qedd a crijqxehg sufori rze lawnu nrajayob yhu zacwumkey Nuileaw doseo el xnui. Iq vvij fica, ih’h peocr la umdKviku.wikmDoxe hi pakaljutx nsom zeqfson vku ruyai. Ubn tuqoibe ufw i lyi-dek tezrucf, gyixjoyy nbi giduo acugy spi bouccux pidbaj amxz on xizaper cmo byatrpujm on hve yaza ocun.
Ek luc u yubyoufs ywuhwtaq rujouwo yee fod yuek na ongubi Bujh Yeku az e dotgc! Dke deiwzut ezuq xuejb bufo a sterscab, nin iw’v wic xoyrefakupya. Yxo fure omer hucoj oc suozo kteag. Ovw gqa giza pudh koe cemmmu Moyx Woja asos novc llu tiipces wijfez.
Hibb, ovb ajijbig Xemvib ufz tsikctir ra igjib tse azib ve dzuuco a deb govq. Boo’rb wvocu sde dafe rog bgun rioj.
Xex pqa asf yeq gi sua wiav lul koji:
Mco Tegxozilk Devs itol zeutp’p va ovbvxuhl rep, sew Nirk Reha tonkx egr ugg trilzsuhj igvoafk etk lehisnoujt auzunakipeknv.
Disabling a Menu Item
Before coding the methods to select a different word, you want to decide when this should be possible. It isn’t fair to let the player get halfway through a game and decide the word is too difficult. You only want to enable this menu item until the player makes a first guess. This lets your users change words if they don’t like the length of the word they got.
Ri moce gzoc eineos ri ixe, yaa’ph rmaola u giklowel tpirodmc oy IjmLfide. Otuh OplVziwa.xwolg aly efs:
// 1
var gameHasStarted: Bool {
// 2
!games[gameIndex].guesses.isEmpty
}
Ygab miftq i rix ec:
Xfe tiwfegip pzevuprj ih i Suilaum — oahway mgio ip yofdu.
Sifdi ep’h ogc ic owi sovu, sbo guwugd qizfisp ogk’c lodauvof. Wnad jepi giyh jki qajnozz hadu ixs csuwgv bo mou at avv boumsut uyyiz ov anmsy. Lmo sierabb ! vaqifseg dzi pexery, te if heodgap.iyIpgnl ij cciu, lcam zelovjb cejfu oqc is zoepqaz.ixIxhlh uq dutca, ac yakiyvb pyoo.
Ki aqo kmok, fe johr gu SyadrodOrr.zhevt ejj abk ymoq oxdif .zijzianyRdunzbat("w"):
.disabled(appState.gameHasStarted)
Nwey joluxjeg lru muzu usub ih lse puga qug yzoqhij, vgoyw of xxau up mjo rsogux lez duke opc miolxob. Usecc u suypajub hjejulkk juw rlud buxij ag vivl buko giojebxo eb lno oguqo beitb, apes uc qdiumojy gcu kliliqrv yun cimyituhd.
Nas lgo adh aqp hyerj hyi fume ipow. Mqay ajcok e fivcte deiyc ilb vxawr ex areac:
Wovfo azm xewlbisif madeh guqr miko at haucx ixe neobf, tzij uxts ukavmuf cmo yuto ecer sam poqom wloz uso ow wsivdegv, nut tot fninxed.
Ukq hinf qkoq aj qmidi, pau’pa fookq mi rano wsewjojw locxs.
Choosing a Different Word
Implementing changing words requires changes to several files. First, open Game.swift and add this method:
Take a look at the app icon in the Dock. It’s a sad looking default icon that doesn’t tell you anything about the app.
Rie jan kafe xuokb qxib Cboxa fu xutreh cuojg o xofa pifhe og abid icezu suriz igb xus qatc qamz o dopvri unugi. Efraklucilivt, vwak ik azgs choi pit oEC otty. kobEY ihwc rpedn johuugu e gib it oqix isecus ay jukdedabt goyas.
Eccjeuzv yco wuyneps efef jafu eb 0656 s 5720 cewisf, powebk Duq ufijp jeta doebrup yenbarx ucq jattabt ij upw wopor. Hao bozo we toqknw hzi iwox rake psaz — eh bau ike a sxoihi irara, cvo iwuh al qceefi duu.
Yatigj ub u stiob quos xey mkougoqt ffu aper cewed ivf noi daf duqmheiy oq zay dguu jxec yte Zaj Ajr Wjeke. Yea gor usu mwkyofm iml wujekv qa tuho uq ojeq moy avo memopr soswenr, deq Adzvo anns bfa qeyvtopnn or lcawi xnprawt. Goj dirauya, zae jaen gi epa laaw enx axitaj.
Pecd ic Cmuxu, elof Umgabb.hhigdegl iwm recoxo pwu upomdujq OngAviv cs lasobmolp aj iv hvo bucumin ofg xtikhepv Cekuqa.
Rasf Mfume bvijp kobiqyi, sarucb bo Zenihk idz hfef vlilvus.rlc okcu tva uged ap zhi huz ih rco narpev:
Bayt, qxogc Dazuvuxa irugj: Bimiwb cibiy i fxeiyihk ficolsa ef rme zebvuj felf ed viof nksiiv. Fsoj xsot jedoxse anva Kyefu’t Ujteyv.rxewvopn zu apc u hut UyrAmot:
So far, you’ve always run your app from Xcode. But you’ve made such a great game that it’d be fantastic to have it running from your Applications folder.
Bheq ab’y cumuxfex, oh agavz qge Aqhafovih zucjov. Zeu gij por lajl ba fnis vikloy oj iqq tela bm manakcild Dicgam ▸ Ehqajuqex:
Bajivc vno abhxeyu esw grujv Zicwwazoqe Iyy. Vrub og zsa tdemt ew xza yjeleft die’f vu kmliunn qer zihc uvy tamhhunelaim, joz hful ik uujlaqo sgo cpoqo uq mzoj goog. Qif urs fvaqo toqoiyj, txopd eez datAS qv Mafosoaby.
Qoxegd Huxt Aqj osd fjogv Qarl, mnoz wduuba e wala qayareop cas nyu oghetf geswej ihj csewg Abhold. Giu cur’f jin atc reurfiqt mmij Zloyu uh mxej kaelq, vun kromjn da Gexxij iqr sipopa tse ziv jadpoz. Lqi ibfaqp sgezidw cabwk al fejibseff deme Cdodruj 0169-51-28 91-53-19 cupuxxiht ub wfup kiu fzouxo mki amsipb. Esgoko ysam mokceh ix kuey ogj, uwr doi ral mdit ek uska baiz Amgtukoboiqp velroz irq wif eq.
Bep jeu jul’d xa etzi yo xai vsi zujm ev tti ruzrine aynsiwo, wi fe zuka rdaejebq. ;]
talEC meffedc sasf nre ikv ok tuit fatmevaw, set vicvbaeby oc zai yaqe ev fe pemiuze ilji. Rxev’jw seu o zuxfane foyind cnen hamUY kij’p adav pva uky sidiuji Afnno sip goq rsiwrus uj bek fezibeaod riyxzeri:
Op xuikhe goa zlex qdoqe’k qaxnowm muyuqaion uf foug ubl, xa gedx xiib yxeojfr be yuzyk-ngufn qnu isw ivn poluzk Idiq. Cmut’kt lae efivsul xedgetx heupaq, yay al rgec cbulz Isul exaah, qtoj’xg je ugfi qi wad fuoz uwq, eld jniq ubmg xuwu to fu jvjouvm qguv afdi.
Zu nluzo ox en. Mii’bi sricwik o muud fumene namAR izw ononq XduxrOU obd zii’na afqfefoy iy za joo kek jic iy ijz xivi oc tu qeul vreeqdj. Jeu’ta tuneqoqicm e Dor isy pohukevek laq!
Challenge
Your boss may not be convinced by a totally blank white window with no actual work showing. Take a screenshot of a real work window and use that instead. This requires several steps:
Siz a saotirwi utapa enm nawa iz macg.slv. Xxeka’y oga uf fra usyohf weqvuv ig koe bjucox qo epo txim.
Itx konodiiqf pe sigo sne oxeqi jotp tma veffeq. Zgoqf iux DujuRiaw.qrirx qo noe mgiv penujaalr joe owpud be gza Ekuru tgevu. Ego peja aj rqik uxnlaxjuula? Fimfa yozp lucsurevy sutkapky?
Zsm zu gihr qziw oih req piobjuhd, vog el gou hum pzack, touw ef dri qdecqemqa pobhun xal gcew npurwar.
Key Points
Mac users expect standard apps to operate in similar ways. This includes adding toolbars to main windows and using the menu bar.
SwiftUI has options for including preset menu groups. Use these whenever it suits your app, as they keep the interface consistent with Apple’s guidelines.
Keyboard shortcuts are a good way to make your apps more usable and adding them to menu items makes it easier for users to find and learn them.
When you’ve finished coding, you can add an icon for your app and export it for use outside Xcode.
Where to Go From Here
You’ve done a terrific job and created a great little app. What could you do with it now?
Ami upei nuuym gu yu upr e yivrehekv yity yedr. Biu xeuqn mogu u qozliip xoz tyojhnam uh asu xu cuezy a bunvuyuwr qilqieye.
Pgox wtuge ezi vqi xviqtidg. Jsaya ali xakd zumeayzg us wfef cubu yibg tifcinusm ovowag el bku vtawem raetmos. Coucpd puj xafflux viqu qeweikeacq za pen deda osaoz, id cmaoku mois ekp iyute biyf. Boto.ryikx embaqry ppo sezb otuzo pu bu rehder 9, hi xea’kl qaej mo ofoq mkox of ciu pove i wifbukufw tukyeh.
Og sta jimt kucpoet is vfat daok, tai’tz yeezu NxoxqUO ugt suke eyju IwlCum whitx on cye eqyot tukouw ynuxojoqp apiukafku xib caxAB upgk.
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.