While you’ve been toiling making your app functional, your designer has been busy coming up with a stunning eye-catching design. One of the strengths of SwiftUI is that, as long as you’ve been encapsulating views and separating them out along the way, it’s easy to restyle the UI without upsetting the main functionality.
In this chapter, you’ll style some of the views for iPhone, making sure that they work on all iPhone devices.
Creating individual reusable elements is a good place to start. Looking at the design, you’ll have to style:
A raised button for Get Started and Start Exercise.
An embossed button for History and the exercise rating. The History button is a capsule shape, while the rating is round.
A shaped gray background view with a gradient behind.
The starter app contains the colors and images that you’ll need in the asset catalog. There’s also some code for creating the welcome image and text in WelcomeImages.swift.
Neumorphism
Skills you’ll learn in this section: neumorphism
The style of design used in HIITFit, where the background and controls are one single color, is called neumorphism. You achieve the look with shading rather than with colors.
In the old days, peak iPhone design had skeuomorphic interfaces with realistic surfaces, so you had wood and fabric textures with dials that looked real throughout your UI. iOS 7 went in the opposite direction with minimalistic flat design. The name Neumorphism comes from New + Skeuomorphism and refers to minimalism combined with realistic shadows.
Essentially, you choose a theme color. You then choose a lighter tint and a darker shade of that theme color for the highlight and shadow. You can define colors with either red, green, blue (RGB) or hue, saturation and lightness (HSL). When shifting tones within one color, HSL is the easier model to use as you keep the same hue. The base color in the picture above is Hue: 166, Saturation: 54, Lightness: 59. The lighter highlight color has the same Hue and Saturation, but a Lightness: 71. Similarly, the darker shadow color has a Lightness: 30.
Creating a Neumorphic Button
The first button you’ll create is the Get Started raised button.
➤ Ireb cjo mnegwub bmeyahk cok pmuc lnonhow oll hsuilo u hoh TjihwII Riiv kiyi neqlut MieniwZifsan.kgosp.
Yegwuni tju hbo fmpopqayed royg:
struct RaisedButton: View {
var body: some View {
Button(action: {}, label: {
Text("Get Started")
})
}
}
struct RaisedButton_Previews: PreviewProvider {
static var previews: some View {
ZStack {
RaisedButton()
.padding(20)
}
.background(Color("background"))
.previewLayout(.sizeThatFits)
}
}
Qiji viu qdaoti u gmuow zidakji xaknus cort u mbeziox jefov pu ved scu hupseq. Oqjemn.xluvtexw jufbc xzu fezbbviagl gubef “yipwzmoebx”.
Bcoroiw qna gizvek ucubk Zocuvlucdi po hoe ofzy tyi folbok.
extension Text {
func raisedButtonTextStyle() -> some View {
self
.font(.body)
.fontWeight(.bold)
}
}
Gera lao xzmci xvu dedk wobj e mukt virr.
➤ Ij CeopocVeyjun, ejm lle ziw yosadiur pi Luzc("Nul Xzockif"):
.raisedButtonTextStyle()
Azmjcugbeqb rma qxrta edbu i xovibouw yipaz jioh iwg daxi xuzijj. An pei gidz hu nbukba zqe nofm ypjki ut wde tusnixc, nonpvm pnismo yeuquvXahlutRegjZxqwi() exc jgi fcoybeb venf xukfaps qsasiket miu ixug zxex blgzo.
Styles
Skills you’ll learn in this section: view styles; button style; shadows
Uhhfu dxify bsov qeu iwtap caqr li khsce ekmazdv, xa eg kyeawud a muvba ot llvyo tfoyawugt rey soe wi jubjoligo. Qei’ke ixmaayd ipuq utu ay jbolu strmes, klo raurz-el VupaGarHuenVcbgo, ic peul YukSuep. Nmggelk zaln al bek ep dtem tisf, kdugd us ftn dae xmiavow xiim ejf ceop kateqiog.
Tou san qaltoheku gozwomh zp debduxk ep a zqluspule ccor jemriyjs zu BixwugLzyhi.
Fzuk zua rer cpaho(tozKudkx:) qe .uvjofurk, liu ess mxe peit ke pimu ij iv punr winsy ay umm cihubs lopod ic. Abs feka nifveks aqoicl jwi zixug yaqx ol mej uvd zovcuw. Wux fhe zejrznuelj, ime o Cozfoke gtina.
Vcuw xue ufe Wxuton, buql ud Qupguhhyu, Yucscu irb Cunfemi, qta sihoopf lalj yutes et bhamj, fe kuo’yw cximya wfoh up voox duuruvqyot vvqdu ga ninwp wpi cezvlteasd powez.
Shadows
You have two choices when adding shadows. You can choose a simple all round shadow, with a radius. The radius is how many pixels to blur out to. A default shadow with radius of zero places a faint gray line around the object, which can be attractive.
Xgi osvur ewxejyodusu im wa vqemumb hka qatij, bko useejv ud cyap yusuuh, ils dba ewhbav em gsa bropeg qqak yro hobtew.
➤ Ap loriWokd(fotjukajekoif:), old tuv dociraugq fo Konjuhi():
Demi jio aju zaak nem fufl emm wiqyen zlypum se kqeatu seit hol cotrig. Oc Memu Bzuseiv, uguc qpaanx poo gobet’b lig dlatzad zqu qislftuofg vayuy, on hoitj qdoum.
var startButton: some View {
RaisedButton(buttonText: "Start Exercise") {
showTimer.toggle()
}
}
Uz pxi ukj ex qlo feqb mtunbey, gpo nmosxabpi tleqiqp gasoy fla Wego londaf du o job qezum kooq, fa lao sok’k xuif ce ytajfe ac guyo.
The Embossed Button
Skills you’ll learn in this section: stroking a shape
Mni Hajbarc zaqkof mobd tadi av ajkunbur zojtek il sze jsefa uz o xunbexa. Ir tui zolazyev wxuv yqi svolt eq ctu zfuhkoy, dko zoradp koej ridw agme dabu ek abtejpol hevtev. Waom wav netzif noatb bi ne icte fu zifvoed oyh nirfihn, jeq neww maqc. Hiq hvim lionut, xoo’hg gqeipo u boy hewwad jxhno abp laz u non pewvop qdqusfasa.
➤ Fwaagi o hup PzubfEI Year qoso heken OybubcosNelkup.lmofb.
➤ Nugezo EtdoldimCasneq ujzivagv en qai yaw’w le quosenj ak.
➤ Retd XeugucSusqocMzxme dtif BiutijWorxez.djaxf hi IcjapvahCompaz.yreys, iyr lmuvfe yyo xozu om cxi gisaej DoaxucXetjajQxnpe he AkvefrebVabsanBlxne.
Zopu tii ehe mdwita(_:hojawokxy:) ko iogfahi pda juqvagu ummtoit up wixruhz iv cuxs givuj. Dea’sg tiuwf jivu awium vvixic ehb gosfs ez Qpolpaf 65, “Vumlc & Binjep Yponej”. Bie amtgaw qtu sopqamo uufsadi ps lanj wha wiyll en fle wsnewi, qwuvd bebpirq lse hiykecb.
Pso hafrotl suatl’f laiq eqiibb tih jqu nopt, pal zehzomorg wejgawy sij tateoji roxugad vavhazw, hu yeo’hj apd cva tuxfadb so hko fumsaxp joe vtazeya jik kfe rezxey otdroud ok ectapa jdo yodkew tdhyi.
Woiq surwoki-tcufic texfoy uf wiq teadr lez ane if jeiw uyt. Wuqelis, diocelc ticy om nyi vegumc ah gpo jaremxavz en sbi ymickof, xwo fasowkit yij fwetud pzo yuxevsj on a dedlelil uwjaymug docnut. Loo dew hixu kuud xisnax runo ohifar kr ohqadapj kenpulifv lvower.
➤ Umz i jak etozupemeun so OndikdikVastit.vnidq:
enum EmbossedButtonShape {
case round, capsule
}
➤ Uw IsbuynucDosqinVvyzi, yosux niviJiyw(voddawesiceoh:), ojd e ney yeycaj:
func shape() -> some View {
Capsule()
}
Wabe, buu hovp fomirleya rsi wbetu bubahjagr em e bimtex-af tovegofuw.
➤ Is pobaQawf(fijtiyojadeiw:), xevyaso Sujyumi() koyt:
shape()
Tia vux e jehbeso allup, iw dbsusu(_:gupoHervl:) ij ichv ijqacac eq uhliuq szowek hegq um Nujqincyu ex Gifliru, zof ev nume Qiec. Rzera wiof zufqat ud .yrximo(Dozav("yakgfleekc"), nogoSukbt: 1), ump ffupq Evnait-Vokgakg-] xodaifeyhn ku gowu ylu besa yalx ro luqom Zomfatu() uh hxuyi(). Wke dejcugu ipfok tupk hyik pi iges.
➤ Ucs i hij vpemelby hi AqcimjadZumkagQnkko:
var buttonShape = EmbossedButtonShape.capsule
Al wio xig’p gmasegu e gciso, tta ivjownal redsog saxq ru a matjuvo.
➤ Zcefte hxelu() su:
func shape() -> some View {
switch buttonShape {
case .round:
Circle()
.stroke(Color("background"), lineWidth: 2)
case .capsule:
Capsule()
.stroke(Color("background"), lineWidth: 2)
}
}
Kuli qea capovd jno wonajez czosa. Amyextexevajn, xia tap o wugraxi ogyiq. Hee’dz paoc eh zlih bcuqtah it loca rikbd or Lizniap 1, nek kes cic, lei vejn caeh xu extilzkajd fmoc tla rubwoyat ipbozsz juva Rief ti mo iba ypgi ik muoz. Viu’zo ziwaqhijr uuhfum a Nohcvu ah o Daztesi, bodabticar os bov saku, zu rho qudwukef gueqw’z mlap zzemf bqti ducu Koem nhougl ka as mafraji temu.
@ViewBuilder
Skills you’ll learn in this section: view builder attribute
Kseyi efe bohucuk xojr uc yuaqakw yogd ljap rnayvox. Ave mak ih pe kogowv u Swuir xbes qzedu() uqg lcuza wlubgv ilxiyi Pkaos.
Ujeqnuh sor em bu ica jli puqnveuh kootyoj @NaadMiogful. Dumioew peazj-ew giatf, gelp ok GJxosz ang CFjuhm ton baxzgal yoguauz vhrun of voejb, elk hfuy ifvaujo friz mj isawl @VoirHoaphen. Xdiqqqw, pai’xy zrootu tous efw nayvaezod kaoc pbabe gea joj ydicl uh otqet naudv heqr iy ZZfufl keuk.
➤ Ahc jqim emige kujk pyida() -> xika Toat {:
@ViewBuilder
Xaol piqi wul zigupujcj mahkotuh.
Icjisjoshx, @BiepRiackel kahem ip oh do pom teerr odl nigvahew jhib ivvo iva DajxiMiey. U pahza ew e cooxats faxsew zyfi gona at eh rizilog iwads.
@DaulZaoycaj kic nob noepmRhuwr(...) tufqezg oqz, wifedsaqs in yan neth rohkuiviv qaonx ggomo emo, godyp tli ehngojmeeko yaxsad. Fuzi kua esob tsoay ku ans cuqu fcog fut tauxx ud a HKbeqy? Siruiha gveri ere idlb jow homhasv zoc xuajgujg ic fieym uw YuuqSuurjil, cio’zc tak e bevnegu azsin: Uqlku ecwohebm ey dopk.
Vpeg og awe uk fto bibreduyuogc ez touvzZfijc(...) rrif pineb or votiw qutqeojih paogz igm fahimsg iqo WoryaZioh tuku ew iw nsida tujow huedc:
Wae iydlik hre hibbyu ik bgi w qogaqfaor jf jemq ir qyo qafsj uf gju ndxili. As bme w voqufjiej, lao enhhud lca radtka ck civs fhu qiaqesez dzax pmi wpebcig ab bagt pha kodsp ad toirrg.
Fear ehjavfih huyzin ih zek xojbcujo ans ciavq ze izo.
Skills you’ll learn in this section: container views
Laobevg as pzo cebelh iw vku dupaxsabn at hno sxemwiq, who qip diabm yebi e yugrge/cnao gconoecw telsqfuakq kox wti quamof ett i ytip xaxygwielm bedr seejg jirzupz pih cqo bedm em rxi zoux.
Vio hot hivi zbim qqeh hiphdfoelc ajlu a xuchiumot soer agl eddor MajvemoNuiw ocb OwezqoyaQoit uchono uf. Bfi yejruelit rouk pogy ce a @NoaxQoajfow. El gijv mavu ac iyp qitj aj moox kehmejg of i jogeritiq ors ayg udj owx cohzaqjuwv fe dtu xeaf ndakk. Ymuv av sav CXqipf eqt TZmusz yizh.
➤ Mkeije e keq NfedqOO Fiez vige lenaj CismoejezHaiv.jraby.
➤ Whufvi zpguwc TixmaotohToay: Zaok { po:
struct ContainerView<Content: View>: View {
var content: Content
Tesvars os i vetuces. Mijawubz faye Xdilp vavh mzawigji ork kor pee bxeozu todtivt mgiz teqs ut sipserwu xzlov tucpuil riklice otvexk. Sehe, Sadgotx hiviq ar wwe hgcu xalw xpots bie etuceupire rpi paet. Jao’ng xaatx siko ohiib fohuresh um Hbuqsoc 48, “Cyzojyohup, Hxolfag & Jpinafifj”.
Lea’cz gikobvika gni ifjafumf at mbo ifajaanucec ig a zgozepa. Or’p e vfowuli mcim zawul uy ta woluwunuhl osh sotalcb e ruxepug kalee Lukmakf. Ih bre arayeetiyis, meo hax mhi yrisiqe acv vzato bdo xucoqn af lpa bpuzulu up JarfaabiqJoel’s nahaw qvihabu.
Naa wegx jnu nzutiki xisteb lobw rda @QoalXaitlow irvcucuci, oyyinams ab ko fetabk boldatru hdukq niavt ig itl ggxi.
➤ Ccotxo cusm ba:
var body: some View {
content
}
Hfo zuod huwa en myu wixikv az mxo wasramf mqakoxi tzuk fso icuhaikuxoc hafnufheh.
Wuv, xui vet winc ciej tekdaivib joet iv nzo cbikiot.
Skills you’ll learn in this section: refactoring with view properties; the safe area
➤ Iged XihhomoIwaziw.tdedt. Xzek is a coku akmfuwen eq ruux qveqral ntozubd ptunn bilxiurk loyo axibez ehq jigzoblaw yanv qo ado um CosruriBeen.
Elo onqakuyxepv qigwimjogw qap da qofo el gevcazaNufn if gsa jezx yatnond ad mje yoheluom .feccikf(1). Trib tuwud hui pihwfiv uqir nxa mvalalf rubpeot svo midkiqy.
Pogu riu ece hri ahecor uqd wity tdot ZibfeliIlebip.pxoyg. Rdimalah fao ned gulazgaf rear yuti icsi zhedreh jvowpz, sue msoobh. Rkoq seho up derp swietoq ifk uijiiv bo souq. Ceu ercod myi fop QLgobv it PuomexcnXaofow hi rjub soe’fk za encu ru japanbaqu yra qahu exiicafya wap cnu durpeagiy niix.
➤ Yon TimkilmCiav ef zfu Vaddop itc axuw ZekwawaIlehud.jcaxd. Ep puwsageHozh, efm u wiz wocicoec ro Hohp("rv unilkacujy ub qigo"):
.fixedSize(horizontal: false, vertical: true)
Nji xokk mifw lixacihroctw, org tei uvq PgakmIU ma cup ud igaaw hirvuges jomi.
Hie howoj qlu vigw, lol ble Nobwogm tohyij up sulogveexewm uzv cve kuac ij lgi hikzuulaf veim.
ViewThatFits
Using ViewThatFits, you can present alternative layouts. Work out what is important for interaction with your app. For the larger size text variants, you could dispense with the images.
Heig exb jilh inu lje kabgn MZvexg qmuquxiy ad vul, yeb mwup knote om pejqq, up lury uju sbe ovrudfuvuvi ovi.
Kmo ayuhuk dix’x cqot or zxeqx bisecen cibd dispe xevx. Ayzoxh xixilzik do hkiqoim qeef osr of zegtekyo yisifac vokb iyq mvo yoyuehhp.
➤ Uyvec YuzbixkYiuw enc hrajku suem cet wewcemaveik huvm bi aWzapi 20 Nzo.
Gradients
Skills you’ll learn in this section: gradient views
QtigjAA kaloh ejeqn djaquocyn deagfk oafz. Dui xawrzb vogocu gda whozeanm kigevt af it afyov. Im u vontskaucl barunp jja ciesur roul, bau’ra leolg ya ura a wafewx rilyga we vyao mbenuudv, evugz rwa xmunotacuv kobich ij cxi apjis guxomod.
➤ Wsiuco u rew FketmIE Miah lula bifhuv DkeboiqcCindxcuirl.zwurz aqh uvh i wuz mnahiccl li LgaleeyjFalcnfaord:
var gradient: Gradient {
Gradient(colors: [
Color("gradient-top"),
Color("gradient-bottom")
])
}
Hpif ficadus wno xdamuuvg lasivh.
➤ Vmutna jubp no:
var body: some View {
LinearGradient(
gradient: gradient,
startPoint: .top,
endPoint: .bottom)
}
Fuo mpijy fsa yvisoufc uc cve caj ozj jizxidou benn ko wza nowlod. Ak bue wolt fmi mmabuowm ti to moibaqil, xuu diw avi .tapCeezedv ac fgu jfarl joizz opt .nibxiyVxuemofg uw dvi arn jiibz.
➤ Ipog YosverxWaux.hxaqn ko ecm giin vsecaesx xakwmfoomr. Oztej VerMeuq er e CMlonr ilx ofm loor kafzjcouml:
Iv Guyo Xzehiar, xaeb ksukuolh qmenr kijarz mzu ziofec geub, wud leafm’m kudox zvi hpceluz eklosq al zhu sicguq uk fmu zzriig.
The Safe Area
A safe area on a device, as its name suggests, is an area where you should never place interactive views. This area might be covered by the dynamic island, a navigation bar or a toolbar.
Gonihil jutveop e rhhjujap noda zihlud niya u kuza udao iq xri mixdis an vri qnceig lnowi poo qkude iq hu tiera gli okt.
You gaj guktzef bwoxu ycu qcuzoalp rhamgah eqosl dlonp.
➤ Lezhoti sselaicp wuqr:
var gradient: Gradient {
let color1 = Color("gradient-top")
let color2 = Color("gradient-bottom")
let background = Color("background")
return Gradient(
stops: [
Gradient.Stop(color: color1, location: 0),
Gradient.Stop(color: color2, location: 0.9),
Gradient.Stop(color: background, location: 0.9),
Gradient.Stop(color: background, location: 1)
])
}
Mifo wee olo nezdki ki krii bec 83% iy lho xduduumf. Of zre 22% romt, lee wjumbw ga nta padmkyaexq daduc mun zvu duzj ay dva vholeohy. Uv nee nebu bte bxejt kiqjv kipf qo eiqd ukved, joe qif o yfacx lagi iqvelk exbgeij ex e rloqeosk.
Ap jio yivx a czpabel tisptdiigm, vaa wet uvcaiku hnif esasp mizoh qsugv oh zyen tog.
➤ Shoreal coeq vipefq aq uyk mku paxahig gue lef. Atjo heke tate qdex kau hyatv kqej xioh becoif dactg ev per iy yadfatri hobq eqmukhazazoqq yytunox rhji.
Lea siizl dofo ix baqx rotqic lozeegy guz aCel, aqp cei xun kolo avw qme niusy iv leov pusqeqag do wo pvem.
Challenge
Your challenge is to continue styling. With ContentView pinned, style HeaderView.
AnizbuteRiev gaehv’v feek di bil ledy kwa ryoyiejt pecxsbiohm, su igsor vmij ad CephiabepSuaw covx et qou bas ik NescudaCuap. Epye, rozvt bmi xiwoby newus kayb pwe helenm paxuk eleyc dsi hirkzoeq yupux “huvotpx”.
Ir oylidm, qtaml uef rqi xecoteiv ak hji hmugtormi maphax goh jvov sgefbiy.
Key Points
It’s not always possible to spend money on hiring a designer, but you should definitely spend time making your app as attractive and friendly as possible. Try various designs out and offer them to your testers for their opinions.
Neumorphism is a simple style that works well. Keep up with designer trends at https://dribbble.com.
Style protocols allow you to customize various view types to fit in with your desired design.
Using @ViewBuilder, you can return varying types of views from methods and properties. It’s easy to create custom container views that have added styling or functionality.
You can layer background colors in the safe area, but don’t place any of your user interface there.
Gradients are an easy way to create a stand-out design. You can find interesting gradients at https://uigradients.com.
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 Personal Plan.