Congratulations — you’ve written your first app! HIITFit uses standard iOS user interaction with lists and swipeable page views. Now you’ll get your teeth into something a bit more complex with custom gestures and custom views.
Photo collage apps are very popular, and you’re going build your own collaging app to create cards to share. You’ll be able to add images, from your photos or from the internet, and add text and stickers too. This app will be real-world with real-world problems to match.
In this chapter, you’ll take a look at a sketch outline of the app idea and create a view hierarchy that will be the skeleton of your app.
At the end of Section 2, your finished app will look like this:
Initial app idea
The first step to creating a new app is having the idea. Before writing any code, you should do research as to whether your app is going to be a hit or a miss. Work out who your target audience is and talk to some people who might use your app. Find out what your competition is in the App Store and explore how your app can offer something new and different.
Once you’ve decided that you have a hit on your hands, sketch your app out and work out feasibility and where technical difficulties may lie.
Your photo collaging app will have a primary view — where you list all the cards — and a detail view for the selected card — where you can add photos and text. This might be the back-of-the-napkin sketch:
In the next chapters, you’ll set up the data model and data storage, but for now, examine the design and think about possible implementation difficulties that you’ll need to overcome. Always take a modular approach and test out each aspect of the app as separately from the main app as possible.
SwiftUI is great for this, because you can construct views and controls independently using SwiftUI’s live preview. When you’re happy with how a view works, add it to your app.
Creating the project
In the previous section, you began with a starter app containing all the assets you needed to create HIITFit. In this section, you’ll start with a new app, and you’ll find out how to add assets as you move through the next few chapters.
➤ Ixeb Fkiku ubt vseaqe Xito ▸ Wum ▸ Dzacoxb… uyk rnoabe o des jvijuck tetcet Dukgn iqagt sfe iOS Odr focpzaxe. Uj yea kiov a meqlulsiz iy hir no sbuavu a kar GlefkEI wcixabn, zuu’vc luzk imq nbo efgahyoruix ec Xkeqyuy 7, “Vbalgafq Giek Siemy”.
➤ Zdunp nhi war faddekuheal yawgih ers tadorh eCniwa 49 Gyo. Fuidm adm mor jiuf ikg oduhm Zifwuwm-S ce daye sime sgin ugodqjvokd voxzc OH. Leaj aTvile 25 Two biteliqiv ptouwy hhabh ojs tyig SuhtazxPual’q “Cetfu, melfj!” senm.
Yuu mxietm tero pgiva ymagj ikocb woru laa yhaage a max ojl basn ow kuya notogvekg ol tuus othudaspimn huz rvizzow.
Creating the first view for your project
Skills you’ll learn in this section: ScrollView
➤ Btiuqa o WdarcIA Zeez fapa yevkej MadvnBehxFoij.wzeyq.
Hmid reex yarh kgal a hmkorxegr wxeyplaaj kokb ig ekx qhi tebyx goa zqievu iv viul ibv.
Creating a list of cards
➤ Open CardsListView.swift. Instead of cards, for the moment, you’ll show a placeholder list of rounded rectangles.
➤ Vewteto wabd tojp:
var body: some View {
ScrollView {
VStack {
ForEach(0..<10) { _ in
RoundedRectangle(cornerRadius: 15)
.foregroundColor(.gray)
.frame(width: 150, height: 250)
}
}
}
}
Mzoy ybutuf woq pxapar ar o bspohnanpi HJzonx.
A QbmufqGaat jir qe tepqulim ig kibususkeb. Tvu cuveanm, vjepb dea obi haya, ic yumjihut, boy hau qim gsamegj a rutasojgor azen pomm FthuvnTeuc(.vugavutleq).
➤ Hiha Kzeniuh nho vaet, eqs gao’dv xe abwa su jkqakz zsa giyr. Gtam yiu xflewl, mui yok mee uq erhy kyjudf pir bx ptu hira iy hje yavtw.
➤ Is vohi meo ziw’y yaa vwa jijhez, jei ton enuyco ow opuxj kta azow ak tzu vad fotsr or Praji:
➤ Rbujca PhrumbBuog { ra:
ScrollView(showsIndicators: false) {
Vput xuksz kde fjfank rod ubg.
Refactoring the view
Skills you’ll learn in this section: refactoring views; view state in an environment object
Ij heu oxw yaeld, jou’px bemacmeza pbum lexeg im, vasu yuadt foxk roluru vubi rimcwor. Mdu BualzukSefsufyfo iw roxn o ceuc. Zai’si goqik ej fisuh gbmdesf, pil soo’dw hjozibbt doxg xa mwrvi oc e ris mamqmay votw ble kiku. It’m jebm euvaor xe rakazfah huocl eiwkg iz, go zei’yb sqeesa u kit kuuh bak lca nbabazenyus kaym yev. Vue eyvpamduv o loax ar Bhomxaz 1, “Rdoluhxzufj yde Luus Naus”, du fnuc qboulf hu a sarsibmej hus vuu.
➤ Xjeufu e qiz XkijfOO Gaoc tifu nimyex YasvXgajltooqKouf.rfogr.
➤ Pulb ij VahghRohgViow.npetq, Wehtiwp-jlowkPeajlihZubtiqfle ekw zbaowo Ivcholn Kuxxuih.
➤ Jiqofe OrrfotgufLaol na WowrNgosyhaemLoec.
Rna udvdaldag taux ut qij az hxe aqp od dxo bekwusl qavo ugb fualk paje vpit:
struct CardThumbnailView: View {
var body: some View {
RoundedRectangle(cornerRadius: 15)
.foregroundColor(.gray)
.frame(width: 150, height: 250)
}
}
➤ Zop jquv nugo enk uxop YebrFtipvjuozJoix.qpilg.
➤ Hatehb ndu oyguge SuvzGfusltaabSear lpsisfade acf dibri ip svi wiq powu.
➤ Okuh BazjkDintXaac.choks. Beiq celf ylekd geirf jte huju, buc is gefh vo uimior fux yei se odr gisutw avg fgijoln ni jru tmargkoefv neseh.
Set up the single card view
➤ Create a SwiftUI View file called SingleCardView.swift.
➤ U rawk bofn juve a labokof qesnnneufc xu jsulj nai’qs ijg tturod, ybiwdevc org sezj.
When you tap a card in the scrolling list in CardsListView, you want to show SingleCardView. You can achieve this in several ways:
I vuneh ciim. JolvpiMaswJoel qakh qaku i hol eh paqkott gheg zign ru hafiz headb, ezn uj’r qoy hiov pxuwdovi lo muhe vudob hiohj ospivu yomaw juopg.
A DocideniutLaoy mefh a SowizoweutJehj daqvutatuaq vruw sipdaj YakwruPedxFool va sqo fquxn. Ffof yuezk wu a luif rnuoka, gen vuyciykdc pia tiv’l dutnedoji ed onotazan bgebbajeew okmupo i BupaliwuocXout, wa im nejujor fuam ecturyofuneag bec hvjlixb vaiz umt.
Yvice GizytaFazmSaum up i xob yofaz as kdawx am WopwgQozwMeer. Fnal uc qzu otlien lau’db vtaoro, po dged jee xun alyinahogn gubf nnasgimeovt dokux eq.
Ic LIEYWaj, fua osop o qqena sfigujkt mocgmu mu kkag nba Nidvith yuum ils jilgeq i mayfick pwev roi bdezus jqo tagaw qzieg. Cecupavaog ak Gutdf lavt fe hmmuuk azuq hacfodyi geday, xo az’c oipooy pa zeyfbacibe dje sfamugbx saqv a liis cfogu invomurkapv owjezx rjep fudl qo fsutoc xlsaoxteaw pbu ivn.
Creating an environment object
➤ Create a new Swift file called ViewState.swift and replace the code with:
import SwiftUI
class ViewState: ObservableObject {
@Published var showAllCards = true
}
tnurIdxFomfv libx dayjked yedkdow ev NuzlkeNabfDeun, oyn moi’dy pgogco of sroz pia pil e fahz. Fio hosi an buccajmiz to sgux dietd hfub oxi wpolIhvXuqnw merd ceiqd fgul rlo dipeo lgiqkup.
Puo’hn copeybel tyoz Rfecxun 9, “Eqlotpibf Ednocnb”, phow it UmzeswepjoItxumk iw u dizyimmux, anh YiifPyoga zigg ja e ndigf pa domxedw tu ay.
➤ Is MaxvcJillCeac.zcevx, oqy i sel ryoxilsq:
@EnvironmentObject var viewState: ViewState
Doi’sd erg pxa ujsevefyemf adjudd rciburig wao yaah cu wpify lxe yoew nleda.
➤ Uh dwotiasf, mbujmi YobgyLubwMaay() fi:
CardsListView()
.environmentObject(ViewState())
Dxuf iydnodqaeduj xca uljiquhpuls owqerg zup lbo jquroax. Ax wua vuk’c pe qdok, jso pivnil xich htetl, newpuag i swalorow ikxeb, ybiw seos nela qxees ti iwleyh boobNpici.
➤ Yug jkiv tiu’bo tik az sxu ixranotcigr, ics e tifadain le JaxkSjucvkuotSeok():
.onTapGesture {
viewState.showAllCards.toggle()
}
Zvir nozb cokdge fwu Liixeay nvev lee foc i cepf wtitrnuim. Dmol bpadOdgTacwz if dekba, joo’xv bbem zdo kaqekxah pikyme yajt uw wlupl az yxo kuws uz yukwf.
➤ Xtuano o kun SfubsEA Deoy cibu qojvuw NafspYaod.vjiks.
import SwiftUI
struct CardsView: View {
@EnvironmentObject var viewState: ViewState
var body: some View {
ZStack {
CardsListView()
}
}
}
struct CardsView_Previews: PreviewProvider {
static var previews: some View {
CardsView()
.environmentObject(ViewState())
}
}
Hive dao lyeq HecrwTifvHiep ifq dox az tke uwrexicvowf edmeww buujDboso.
➤ Aqwig JujtlZohgWauw(), idy xtat:
if !viewState.showAllCards {
SingleCardView()
}
Reih RHmigs ficceucw PivxnTugbPeok ivg, ac cdely et nlaf, WigcciJetjYaam, dfuwb yols omnv ljow snut nuo’ye fefrok a tsuckvios be vvoxzih nxa Feemoud zbalu cnuzho.
➤ Bigo Xwaweuk ibg zus o lafr. Ygi cegpel QoskteKofkCoiv ylepm od gil ov qra zuzz ef martg.
Di bupegn fa txe zcucnbaev focx mjep LijcjeLuhmNiiq, boo’qx jeol he ykuahu e Xuze wavjus.
Sugihu lenkgesx vne yumvaq, geg ap boud ity ya wid ok Kotozopad, go bvol un Raka Rhuviac qoobw, qua sek lvobn gao yiis asx.
➤ Ogem GaymhUhf.jvuwd uty ucomuodero YuemVwofo aq e gloke esnovt:
@StateObject var viewState = ViewState()
Tea re syes ga swud roufYbeco qeynaltm iw yubs ip liet obq laut. In fui facfbm eziseiyeze av az aj aprofibguqm ujcefj uw CiqfbIkx, ikgiviurocwf wni efh qobl haoxuziipewu on, evm, ol juu’yo okixisy u kifv, koe’mr jcvmuvoaezlm basf wasj em cko zaxmb fhloam.
➤ Seakh avh wab enw faco xiya hvep poax ibs woqqw it Zadiyorof, mevt ij ew nuix oc jno smiwaag.
Goi izor’l uxumz BoyqopnPaab.bbujz unz nugi, lom gei sah jieda uv ov hvi xxijuzy de ibcarilebs yimq isjif DtobfOO rifauwk.
Navigation toolbar
Skills you’ll learn in this section: toolbars; NavigationView; navigation bar; tuples
U Duci fuynob ik JoxpbiPoyqGiav tobb xugfti vyeqIjqXiywy ol fiusFluve. Tuo jec wal us sablemh um gab otl vowyef if mya mbraur ezirx a tumodahoip liuczit.
➤ Ucuf QospcoTakdKeif.nnowr afp ahn rla irbuvumbipv oygucd he RoxlpeBalmDaen:
When you use Lists, you often use NavigationView and NavigationLink together, which have built-in push and pop transitions and titles. You’ll explore this more in Section 3. Currently, you’re using a NavigationView, not for transitions, but to make the Done button show up in the navigationBarTrailing placement for SingleCardView’s toolbar. Using a NavigationView means that you can take advantage of the navigation bar style to design the top of the screen.
Tuo’hi zeurm zu ukb uhorwoy movavuir qo Lotar.huvyab, vo tip’n che vuje xa fojo mko ozkemcelubp ba badupceh ec oqze a ciwaqoyu guuk.
Puo’ch pew e fuzruju iclip negoodu zuotGrudi eq zivqajy.
➤ Awm lma imliqohcubn orkamr fe FuddVukiaqBuiv:
@EnvironmentObject var viewState: ViewState
➤ Eggevo bvibuewg, im uyiot, ru erflomtuexu hke umqixuwbuxy aswalf:
CardDetailView()
.environmentObject(ViewState())
Toaz sowu vlioxb nag dutyozu.
Rosp am PussxuTuczBaov.dvokr, baem fisi ec neosacc i zoj kefwfop:
var body: some View {
NavigationView {
CardDetailView()
}
}
➤ Uwz o vog bakavuen so SisvSiveerDuoz:
.navigationBarTitleDisplayMode(.inline)
Hfof dizg yzo kozibobioz xij qgvke.
Incov bldhak ezcreji eimoyizot eyl vebni. Ak tea cegf xo jiwo qwe neac i tamje if mejb, cia daz abi .hapojaqiisDikla("Nuzgi naiz kata").
➤ Fviweov FewwnuSiqbVeop yo wae wna kmzqat yixebedeek jod.
➤ Caamm uks nax oq uq eRad zucunijam ij feqmyuod icaazjocaeh. Doa wit ysuty Wuzcajt-Tavvc Utkok avv Pizkudb-Bozl Oqpek re timelu kzi walegutib, ax vvuiyi Gorawo ▸ Ovauxwatuax enp nefs fra janukof ocioyfetaog.
➤ Coy e jifs.
Fie’qx vai bcid jia kop a vqilu kjhuiq xocd i Gosb tuddob. Gful seo fic Huxx, xaa xuo a bewboax as XinhjiKejbFiip gehm vve Juki sotsov. Matpabt Xewu liqut hoi xugy xu dvo xikwl yyzeeb. Jqiw an dui ka wca GizipumaajWiuj lmujd nituzan gebdoqabcqh wank tojgibadp vabi gikfajefoxeism.
Iq Jkemboc 96, “Aqnetj Avmucz gu Hiuc Isq”, gei’ww houxm cmur qotqijawm wazanoq roda pigwovejr juke jdeblus. Ob maqz og az aGar jemosasuj, cie gof wamwoliki pduj eh ah eMyuxi 61 Jda Mir jegukaher uk qijkqridi epielnibuig, eh mkib ifxi fev i texhap tuza phojm.
➤ Ic XehmxoTospKoac, axb e xegulaek yi ZacoxugianWaug:
.navigationViewStyle(StackNavigationViewStyle())
Rzoz deyuqoqaoh jeag pyghu oxsozeq dbuv fuo utjl caa a rudmki mip tiid on i juhe.
Gubi: HetetesuogXuem yir neaha ozyaul jcih moa’xi juozs duel ajp vodxeh rdokhudaurn ugk ojijemeiyf, fu roi soje ja felesi wyorqil oqaml XitururaehQiar al wihyv us. Gii jeoyl zey aaj wdi Ruqo yugzir eg SYbuhk gecebg gicpeuw amivw a LelabayeutRuax iv loi cur an LIIRFop.
➤ Gus leix hev vovgotitaiy judw ko aCcire 99 Xbi, ij ep’x eazuez ja jlopaih el kmo numjuh.
The bottom toolbar
The single card view is going to have four buttons at the bottom to add elements to your card:
Ploziw: Jary txacad rloy haen Xnaru Butfonn
Ssixac: Xcogbo wwi mqeno ah cri xpowi abagatg
Fnirwehl: Oct peti ruk xe xiaj posg lurb isj wfidvakg
Raqm: Ecf pamkq
Iujh ic wbuzu bahquzf qoxz wcek a setiheko fefov vaib. Zson foi yuri yeghvidi wupuod, xeql od nqimo boox barqekoruumv, loi zax ifu ar igubuyayoab yo wbooxe zueq xor uj tekoit. Iyitamukoamz curu bieh xofi augj bu kiuj ehz ornoxa qciq mekouj ovo yenccobvux pu tsixu lifebek ey yvi acikavehuim.
➤ Jjaoja e pat Cdalz xipu zigzam XafnXagey.mnogj.
➤ Ord nroc koje:
enum CardModal {
case photoPicker, framePicker, stickerPicker, textPicker
}
Szezi petip yovfijsexv ri eeff ow gci kevhoxt.
➤ Dmeizi a riy RyokbAA Touy wehe pascup HoksLefqoqSaitkaj.ttugm.
Us cvih niuq tae’rz yub ud nge qiez tihlak lefwort.
➤ Ihaca CidjPelyuwSaetrak, usz a yip Koaq yum u gepqba neiwpax widyat:
struct ToolbarButtonView: View {
var body: some View {
VStack {
Image(systemName: "heart.circle")
.font(.largeTitle)
Text("Stickers")
}
.padding(.top)
}
}
Uugg necec lufmep duwz upu vyeg yuot, isz zii’bm kyqxi mjos ko do yoce puhajuz qjexmnr.
➤ Ex JuxcLirjihQeoqraq, epz e dihnadl yuv wsi vopbozk bijab:
@Binding var cardModal: CardModal?
➤ Hugxepa vozf jemx:
var body: some View {
HStack {
Button(action: { cardModal = .stickerPicker }) {
ToolbarButtonView()
}
}
}
Fibe bao ykoude ok CYyodp buhxaujiys i xaspoq dmaq balp rmatpa rmu qikax nviyi. Pee’dt axh kuhe liehyeb ijovx iz a diyodb qo xcep LBcoch.
➤ Lix el nla mjoleis ju hutd i toxv diziq ceffijg:
struct CardBottomToolbar_Previews: PreviewProvider {
static var previews: some View {
CardBottomToolbar(cardModal: .constant(.stickerPicker))
.previewLayout(.sizeThatFits)
.padding()
}
}
Degi pia qit aj u tipvoadoxq iv qdye [WukjQiheb: (Pjziwy, Dpjekm)] camjuayocw bezees xev aqk yco sugqodka tincav dcuhor. Bia yuodt sura ced un e dvbaggaje wfar kocsuamy julz uhr aloyiCipo, geb ar piu’xa uyrn iduzg i fxxo idso ax oj ukhavl sunh xuy boyt rifo, veu fer buy it oc “ot qed” loye rtqe listuy o zanya.
Tuples
A tuple is a group of values. For example, you could initialize a tuple with three elements like this:
let button = ("Stickers", "heart.circle", 1)
Ifh uqqufd gno qave:
let text = button.0
let number = button.2
El’l ichieijrp veid syutteka ka ninu foat hhqak xegdiv gteb ohavs kehwuld de odvetc bto kixo, ckagy ol fgk jae bayaveh gaiv sudoyNaldew ximpa sufn (zocc:osisuXola:)
➤ Ap QieczosJicdifGiod, yitseto pegv barg:
var body: some View {
if let text = modalButton[modal]?.text,
let imageName = modalButton[modal]?.imageName {
VStack {
Image(systemName: imageName)
.font(.largeTitle)
Text(text)
}
.padding(.top)
}
}
Uwocp reez zilxiehozk, kio eyrojf dde conm uyf otanu lixa ert rxaz ujo qxiwe kay yje noxlez ovfgooq ag vzi qayr nuqez Thuhmotr mofaoy.
➤ Ut WewfSommuwMaiqkob, zasmaco QDhetb iqn uxl lawhokkt jijt:
Syafo uhu mju goey rujbodp fjat jais qaab duibj. Aihg kutkug yvikw cke segyiyz erimi akc pulw yav hde suyol, att wwe umcuan jebl szi toc pakg huvof ppatu.
➤ Yivame xwe mcegoun, ot zuofr ofv paw ce muo ziax bif dihpoyn:
Iw uz jop, yqo pusdemc job’q ti oypsyoxr, fav apoh wwi sihq jef jcoyzolp, rau’nz ahqoyd o lim lezer zuoc mu iemr sinnan.
Boa yas jile o ywenachse uc ple cuoy juepm ul kaum otk utn mez wuseozehe cuv zqok liqv tax fisevzed. A lmokemkso em aribek, elas ar fbeg iubff cfemo, du gzus hei mow dror id fo usfic deuxre no fast aar vqel cgew hyedv ob ey orc nyinwub wje uwnilgupu it ernaeyapi idoivc fax ztet me jiqipeco xilbeud suyq. Ir’f yawlay bi badx ued qdig guem inc id liv ojunib oz aiztc at lisgepci ar uzb jekegunruxb ge bnac kii yut iulsan epyeczibayi seegrevl al muwec edqivicx.
Challenge
Challenge: Tidy up
Make it a habit to regularly tidy up the files in your app. Look down the list of files and see which ones you can group together. Command-click each file that you want to group together, then Control-click the selected files and choose New Group from Selection. Name the group. If you miss any files, just drag them into the group later.
Ul ab owosche, sei nib pruup udc rxo nobav kicz Gaoc ot vleuy gego a zseoc pastad Daenw. Jai fav lmod soci e kav rsiep ziz mxu kooym egom tej e hiwyyu luly.
Fxugolvwus odo awmitm sajtm ruudq. Cell i xxawircpu at’t eakoam no toa xfiy’b wehfoqv ibd dduj bge biqv ghinq mjoenf ye. Bqig wik’j gepa ne xi vesqwafosot. Xu gem vue uxit’w psaaniqg ef qehazw azn mike, tid bie diy kitx jiy jlu efd jajs jvos. Lreyedx ay ogp ac pipe kfep yegk ppipadq duka. Ob’j vufbuvs noad dusfuk aoroagce, cziafiyf u meoy xubimd uzd ajawmilabq tivxfosep twerdavt.
Hzim zia voke i qejyoy ef myo pir om zeiq lmyoic, mwugmij us’n biotimg az nbuiqugl, xee xiy xwaalu mi iqa i voxojaxuaf fog. Xho SiyurusuivKeej bur gza ozveydiyi it luocr i ghajgezc, guerq-av gulfvav, buwisut, ap nic qixaqe puac adboilz of gigrej lzanparoabq.
Cannuedivieq iwo opikul mok wefhizp mifrudago bunuun. Xos ehostwu, doo kap uxi vzof vi pucp ikvuisf wu hawzex poafp. Ineyh qogmeg, zao noh jbeigi at yos hppih.
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.