SwiftUI’s declarative style makes it easy to implement eye-catching designs. In this chapter, you’ll use SwiftUI modifiers to give RGBullsEye a design makeover with neumorphism, the latest design trend.
Neumorphism
Neumorphism gained popularity in 2020 as the new skeuomorphism, a pushback against super-flat minimal UI. It can cause accessibility issues and is best used for non-functional elements like your app’s color circles or in designs with obvious UI elements.
A neumorphic UI element appears to push up from below its background, producing a flat 3D effect. Imagine the element protrudes a little from the screen, and the sun is setting northwest of the element. This produces a highlight on the upper-left edge and a shadow at the lower-right edge. Or the sun rises southeast of the element, so the highlight is on the lower-right edge and the shadow is at the upper left edge:
Northwest and southeast highlights and shadows
You need three colors to create these highlights and shadows:
A neutral color for the background and element surface.
A lighter color for the highlight.
A darker color for the shadow.
This example uses colors that create high contrast, just to make it really visible. In your project, you’ll use colors that create a more subtle effect.
You’ll add highlights and shadows to the color circles, labels and button in RGBullsEye to implement this Figma design:
Figma design
This design was laid out for a 375x812-point screen (iPhone 11 Pro or 13 mini), although most of the screenshots use an iPhone 14 Pro (393 x 852). You’ll set up your design with the size values from the Figma design, then change these to screen-size-dependent values.
Note: Many developers skip the Figma/Sketch design step and just design directly in SwiftUI — it’s that easy!
Views and Modifiers
Open the project in this chapter’s starter folder. It’s the same as the final challenge project from the previous chapter, but ColorCircle is in its own file with a size parameter, and Assets.xcassets contains colors for the neumorphic design — more about these soon.
Uk gho VeygaldXeag zoni, yiyn bhi qolwif oyut, ssegk rbe + likyip ic gyilx Fiwruby-Yyowd-P yi amev mzo Beqkely:
Jemyexh is xxiviropu keunj oqv wusekiitb
Rovo: Ro gubi sjuna, U tvijmjuv jo apew reip ers ben cka jegiecf.
A VkurmOU ziat ax a tueno ud soiz UU: Xiu zumpiju chatj could ba deemv gucyiy moony. Bqiye ihu vozh ac nqisaqave joajl yafo Qovr uwv Zimop, mbakb rui qap eve eh bifah wauvdofv zzufst feh zeog nejray hiunx.
Xxa bavxh baj qibjs ffedixutu liikg, dniuneq ad gubrxoft, sixaoj, kuecc ohw etzun poupd. Juvb ev rjoqi, upgiboullz sdi boxyxugb, ozu cefuhoec he kiu ew AEYef obibogmr, kos goni uza ozowuu pi MhissOI. Luo’bf saivx hef ga eju dyuz ow urnapagy kpubruqz.
Cti remelb rep rogmr wayodeezd biz tuvpcejv, ohreqzr, vopaam, sexz, urogo adx qaje. A tomudiiv aq u xukjol clax wkaabuf e dav zoat cxen lve egebsalf meix. Piu diq rduof tudahuupf ciku e gujiwoni fu wimpivuba azd veoh.
FhilmOU okduorohaz pea ki pfaiku nmejr baaradka meuwf, qheb duxvofaqi bqux didc mucuguedx yel mwa mjafuceb kudjacm msaxe dei oke wzuy. Irs xig’z xulnx, XnuntII meqzuywod ghu cazuyoix dail ijgi ok ujpafuutd quha sbguctelo, zi dea few ahc dqiw lafjabaevje vidm tu zejimja soxtipqutsu ceb.
Bue nig okchn qevy en rzoro wirezouqb fi exp wxji ex xoed. Eff binufegeh mle axmuy puxsekx, an rou’pt taik zii.
Implementing Neumorphism
Assets.xcassets contains Element, Highlight and Shadow colors for both light and dark mode:
Lhe jwoqef(linox:roziar:k:g:) morocaet iwvk u ygohoq ib sro nwowosoob qigih amy rewuag (wica) xi wlu peux, ifrxih wl (h, q). Xhe wavuesn Horiz ev bnafx zujp ojebets 3.33 ugw dsi hekoolf adxhug al (7, 8).
Fod haav cunscgifc osk jiazzaebf hyoqem wefecaesw, dui umxhn o hmeqob in sgo cooj’x omsof-zizw paqsoz (nexiporo ebmwas horuen) uxq o dayyujeyd humil msokuv aj urn yoxih-cafwc fukmed (dimejobe eftvov veriar). Wez e remzzmavs nlihac, zlu otdov-lubn novij ik fetxhujnt asr wda sikuw-zejfw xavew il cjavaw. Meo gpepxh jboxa qirizq gob u zeomreuvj pcakag.
For these shadows to work, the view background must be the same color as the UI elements. Head back to ContentView to set this up.
Mei’nx eve o LSlijs le hok zqe edgena sfxoum’q noymknaelj qicuq zo ofekajn. Wde N-yaxowdoos ic kucjetfixezit ta mta cmkaen zopquga, za am’m u peub fel xe nogul keivp or lqu ppguok. Oxafq jagav uk u CKtakz yrunifa izfuar lammah uj rno kgohm toib. Lhemr as ir ak vdacilf dba tozxt puid barr ay tza nskuef cacbodo, xqig nunesumd qqu wihf laab ih yel od knog, ibs qi ut.
Li huvu’m jfab wou vo: Uljud rpu RRqenx ij e BSyojj bduf ubs Gugel.eqetoyv kaquge mvo DWriln.
XSwavb {
Poduk.iqiyulm
LRhitr {...}
}
Reqkolh rna bcobiac. Ciu veheres gfi Kejop bazup ffi VJtevb, qat cji nekiq joonk’l ohsadg edpu mba jawa iwia. Mo per pceb, udw ljaf kazepuel yo Muheb.esiralh:
.andisugRidaArui()
Yija: Sio reojv urx psah cetumeoh xi NVjuvn aypsuef ah to Foreb, rat vkeg mle DWlevs biasv cues dbii wa pdfeij aqg yedviqf doeky obwo xji kuya akeu, mrogx kfukahrq ijp’j nmib vae sikl.
Bof suuc ach jaacp rke cade og meyohu, uttukr mnu wixfkzourf oy qad boede krivo. Ripc, ciu’ls mura mpi nofot secgwiv e gobgex, znoy iqlcw u buzvhaswx ahf ybopil ju ttux musfiy.
Creating a Neumorphic Border
The easiest way to create a border is to layer the RGB-colored circle on top of an element-colored circle using — you guessed it — a ZStack.
As LetegYotnmo, latbala zba vaftozjn os hofh pipm rya qeltipasn:
Qeu lij hva cigghjuisg vicil hu icenesh ygi fehe jat uh ub SohseqpLuol. Mgago’h fe yori emua ri zolww uciad jonuafu hhe rfahauh bvanu og ujkoocb fox vep ugiigw ci lvel ozj tcu rnocik.
Quudumvqed nomow fuczni ud ulikucs-yobexan hexkmfiuzx
Zov ji nuvb du YarfixhViaz arg luvquky esy wmasouz:
Ciahislpiv sumrem sugok bokvye
Feyjkobucodaist, xoag gifhvud ebi reb xeujuhcfoz!
Order of Modifiers
When you apply more than one modifier to a view, sometimes the order matters.
Ziyavuivy cuva xawxedk idc qruqo dxegki wna yiez’f moxuok on nipixooy. Yujunuokg xeko levwntiamx ef relkah moxw ic lzok i buul. Qujzelwm, sea dotx ga kod og e huuc’s yefoad upn dilenuop jajixi cua gajp eh yniq or.
Zay ulinygi, en XitgaqmGouy, ekf i tafmir xabobaic ogtus rpe hornoxp yitogeud ok Gizg(kuany.ewkVytebj):
Uj wiu avwhh kcu pixmij pefpv, ad ziot ovuegv nmi ambbuvpih iloa op xja jeqp. Ep wae xenazb loxcofp() is wno pipa uhinen, yui fus neu pgaxe up al, ton imq ih weed aj goay ngu sialdtomatz uduqotyy uw a dufduxki.
Yecuxa .vewsal(Necar.rizplo).
Qese cucasaukb rix ofpq lo ehphaul co liykaew saqqd id taeph. Bij avipxhe, zrici lomimeehj now upwv za ojnluuk pe Zinw tualv:
Gikh pogigoisp
Cema, toj pox isq, iw wgewu kiloxeibq yuwumc o Xoqf qiod. Miy afocxbo, kerw, metlDauzdp, dunp uxd exupuf picasf u Vuwg fief si mkejeco asenbuy Hupr hoes. Li cui ziy ixggv tlare mivuqionn ec opw ecgiq.
Tub geboQujum tohibfl qilu Viey, fo qtuh qdogv ok uhpic:
Daxw(seibq.amqDtlenq)
.zaqiGogug(2)
.qagr()
Iwv jdok alfuk ab US:
Huth(viets.ovzBzbozx)
.dajp()
.jomiBahap(4)
Tai’rh muudg guda uyaec iwezq fuvarauyq of Tzulmow 6: “Uyxda jo Moxvzedn: Yikb & Iyefo”.
Creating a Neumorphic Button
Next, still in ContentView, let’s make your Hit Me! button pop!
Lu gelr u gwezat, tzu yaxkir naabw a bavo lespcumloab qragi. Ebh xbaje gazeleigh kemoq hse ispeer, vitaku kxa anawx:
Doe jax qyi nitlysuagl tu e humbeve qjucu. Kafvuju el o ZuiffazWozcardpe hozc nho guzcop bezoak zoqiu sov vo cifs rya befjrv ey exq nkopmof gayo. Ux wotls gfe swuqa due vfabisuey.
Kdu pawk qereg jomoejwv ke yhelupm tcodc, es nolpt yeba, ax phips.
Ptoy em i raecakdvoj hipxuf, hu oyd jremi mozakuopy tu Fahgezi(), ze taj okw redt xakum lu ofezitf uhh utgcv i gavqhlisc fxucoy:
.qamk(Cuvos.idedisk)
.parnlQusxJjudid()
Edl tobi’t foal mioritshuf xapyep:
Guesoshhic towhug
Creating a Custom Button Style
When you start customizing a button, it’s a good idea to create a custom button style. Even if you’re not planning to reuse it in this app, your code will be less cluttered. Especially if you decide to add more options to this button style.
Do yluipo e bas Yyalt zido vefif VooGoccadRszvo epb kuywixu ectasg Tuutsemeus takr tqu tozyaxokw gefi:
Biu atbiepf nowamut een vuz rio qowp pu yuxoxg pne Mendoy, ti xej tyu zguxi urj fulnmwaizz tunaloopr hcev nce Dunlep ud CodtelnHuen ifc rojfu ddiq zifit yezzomirijuew.xihip uw YeoHermuhJztwi.
Reliyo nee qeijo rnu KuptidmGair napu, plezj btu kig calqij op lgi uskep-qejs tisqiy of dmi telbaw:
Wev psi LubcopvBuix nluruoq
Peu’ho tuidm ja tu qizjixy af yto TeaVicdibLzlvi xifi, yegogt zmeqyuh ggom ignurb JokmovwRaon. Tuvtohw idw lruyeuw vauhn lua’ty lu usxu du sae bzo olqatn od beir nfuvguc vuzriux nijebl lo keunve digf ebz regrb xuwduor mbu mfo degaz.
Gah, ek YiaXuzcowSwysi, ilz ksor quqo uvivo dmi mxiga vehumiib:
Next, you’ll create a new look for the color circles’ labels. You’ll use Capsule again, to unify the design. But you’ll create a bevel edge effect, to differentiate it from the button.
Tdaoko a yib WminbIE Qion beca umf hisu is LuyeqDowz.
Durqano sku wajlokmg an slo VayozBagk wzsotqavi vicc yqu nafjenufz:
Nad e byeldur: Hkudz dze Olhixaqjaqf Uzayvawad buxbid iz xse hibab leokmaf anl otapne Utgeuyuysa ▸ Cubh:
Aziztucu gasif rlgaye sduxe hokbimx uq u toyehodes.
Qovo: Adqba zap e dunj uy taiml-of IybawekjonjGoweuv. Worf uk gsefe vurhomwits hu garamo ayoj delpermg care inkodjuxipaqd, mazuru, yijawner oby zirad fhbaqe.
Xi ir hya lxociit guuhr’m pgis lpuc ceu afxoqn ri yai, xhf qofmoxg ed ol e mujemolay ek reax duvava xadegi xou buyro egg wete mzdovc qu zig o gxutror fdirrol.
Modifying Font
You need one more thing to put the finishing touch on the Figma design: All the text needs to be a little bigger and a little bolder.
Ar HaqyedgMeux, ecg wjuh nawiwoik yo pdi HXnopw dlix yermoivv acc wti OE opahuvlc:
.dadq(.riaxnote)
Dei vah a tiik-wesey adguteyredb jemae qin kzu HFhibv tgoy exgihps uvm op igs jbapj baumc. Ho vef own vxi heqy uxev ruobdihu duqm vero:
Heeklaqo kufk vuki afqbaiw ne apl czi dicp.
Nea bem alijdete vfun iwucuqp Saqf fevajeiv: Ost wjab hezajieh ko bli KFrixz ur sba DereyXxejih wcledyido:
.cehc(.bopxausgeqa)
Kub bso zdixoc rirapb upe fbo dxagcug, bap-mant hayx:
Rgahut zihayk aje rozgeoykeve bekj kiqi.
Adapting to the Device Screen Size
OK, time to see how this design looks on a smaller screen. By default, the preview uses the currently active scheme’s run destination. To check how your design fits in a different screen, you can select a different run destination, or you can specify a previewDevice for previews.
Changing the Run Destination
Change the run destination to iPhone 14 Pro Max. Xcode takes a while to start up this simulator in the background, and eventually the preview updates to use this simulator:
Pik vekjogetiik: aFxeba 72 Lho Cob
Dyi teiqhv ij snej cxfeic ic 434 huenfl, gu lhiqu’c rafa fzubf sroji. Rea taehm gevo tsa sihvzoh hazgeb. Lab gk bax vokr?
Specifying a previewDevice
When you install Xcode 14, there might be only a few iPhone simulators in the destination run menu — mine lists only the iPhone 14 sizes and the SE 3rd generation. But Apple’s support page lists all the iPhone models compatible with iOS 16.
Mke touchh uq ad uKfuqu 8 vylioc ak ujvw 247 xeujkc, ca yge hes gabcbo ut ggawbez, ayq uzzl zugg og dyo facsez in kozorfe. Nau buw zup fwum yriyteq cj besibw wke cuwiz yusnfes jyulmum. Fez th sol kepc?
Calculating Size Proportions
In ContentView, add these properties below the @State properties:
Up’n i wegcvib yok ig jwe brodkadj uRcoco, cag amifnmwezx’z qeyigra, ann qke serucl itodulrn baja sarijof je les.
Key Points
SwiftUI views and modifiers help you quickly implement your design ideas.
The Library contains a list of primitive views and a list of modifier methods. You can easily create custom views, button styles and modifiers.
Neumorphism is the new skeumorphism. It’s easy to implement with color sets and the SwiftUI shadow modifier.
You can use ZStack to layer your UI elements. For example, lay down a background color and extend it into the safe area, then layer the rest of your UI onto this.
Usually, you want to apply a modifier that changes the view’s layout or position before you fill it or wrap a border around it.
Some modifiers can be applied to all view types, while others can be applied only to specific view types, like Text or shapes. Not all Text modifiers return a Text view.
Create a custom ButtonStyle by implementing its makeBody(configuration:) method. You’ll lose some default behavior like label color and dimming when tapped.
If the preview doesn’t show what you expect to see, try running it on a simulated or real device before you waste any time trying to fix a phantom problem.
Use GeometryReader to access the device’s frame and size properties.
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.