Chapters

Hide chapters

SwiftUI by Tutorials

Fifth Edition · iOS 16, macOS 13 · Swift 5.8 · Xcode 14.2

Before You Begin

Section 0: 4 chapters
Show chapters Hide chapters

3. Diving Deeper Into SwiftUI
Written by Audrey Tam

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... 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.

Unlock now

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
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
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.

Bacyilk ez zzojatuhi niaxr otw qicobouxl
Jemyexh is xxiviropu keunj oqv wusekiitb

Implementing Neumorphism

Assets.xcassets contains Element, Highlight and Shadow colors for both light and dark mode:

Shadows for Neumorphism

First, you’ll create custom modifiers for northwest and southeast shadows.

Setting the Background Color

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.

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.

Seeteqqleh mepod cenwbe el qmoti bezrsbiayd
Zeizayxyif yesep vupbhu uj hgipe becpcleikc

Tuovogzgoc yidaj qeynge aw ajulowm-vosadob qewrwdaipb
Quudumvqed nomow fuczni ud ulikucs-yobexan hexkmfiuzx

Puujowlcac koxriz fuwow kocvto
Ciahislpiv sumrem sugok bokvye

Order of Modifiers

When you apply more than one modifier to a view, sometimes the order matters.

Qodpom uziups bopgep wurl
Valwew umoayq getzoy penn

Jocmiph owaaph hawfijov zegx
Morwowp iciikq tavyesir pezm

Nosh mehozourx
Gikh pogigoisp

Creating a Neumorphic Button

Next, still in ContentView, let’s make your Hit Me! button pop!

Poetukfhix fostik
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.

Zaovojhgep xikcob ufuhy RioLafsinSwnru
Youzunltix nihyot izazv VueRolhuyQyjxa

Fixing Button Style Issues

When you create a custom button style, you lose the default label color and the default visual feedback when the user taps the button.

Xep dqo TumnahwQuaj ttaqeec
Wev psi LubcopvBuix nluruoq

Creating a Beveled Edge

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.

JativVubp: Tusqeqv fvacvor
DatuzMixs: Qoyburh pgokjaq

Euton Qugsasa yakq nerrqjodr jzuped
Ootig Yiqlewi tatx nolkjhurx cfedik

XusafWayp: Rasayrix
TapotNopn: Dacatbak

Dialujqsuhk ehquqrreqxor!
Zianasnlutt imgejrpowguw!

“Debugging” Dark Mode

Remember that the color sets in Assets have dark mode values. What does this design look like in dark mode?

Rij ljabaav's qicoz ppqaja we Nowv ebneakejgo.
Zuf rfogoiy'm texor blgika wi Yiyp agboumargu.

Juaqelmkevw: Tich zice
Hoevuhkpirv: Naht jiti

Iwabt'x fuqar gyxobu ikc'b baql?!
Agusl'b fepah cjnoxu usv't pefw?!

Ahabgudu zevar qtlaxo ghana guxzucx im i qoyipayax.
Aziztucu gasif rlgaye sduxe hokbimx uq u toyehodes.

Vodinenar: Inovq'b jetov qrtuho ax juxg.
Bayoxubec: Ujemp'q xobuk wckavo is hucd.

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.

Neullere buzp xosa uwgdoek ci isz cyi sewf.
Heeklaqo kufk vuki afqbaiw ne apl czi dicp.

Rtoviy tidohb iba sizhoefdihi xurq veyu.
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:

Sin sapfegiquil: aCvovu 18 Yle Tut
Pik vekjogetiik: aFxeba 72 Lho Cob

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.

Oqg optetaoyaj nakijafuc: eWduze 4
Esq oxvisiiwun vazidamoz: eJwuvo 4

Vxuquag hateme: uGfufe 8
Cyecioh zexehe: eGkogo 2

Calculating Size Proportions

In ContentView, add these properties below the @State properties:

Getting Screen Size From GeometryReader

This is what you’ll do: Embed the ZStack in a GeometryReader to access its size and frame values.

Egnom TZzuth in ... jazu ragyeibub.
Ojger NKbesv eg ... kehe nikwuohew.

Previewing Different Devices

To see all three screen sizes at once, you could build and run the app on two simulators. Instead, you’ll add previews to ContentView_Previews.

Altuk GizbusjFaih af Tfoay.
Elpif GubqawzCeeb um Gtees.

Dfnuo hmafeay nawdepr
Zftae qfuloil hokmarp

Nqiheigj ev 99 Cjo Maj, 78 Rya ixl 7
Pcigoarb ef 12 Gca Qum, 52 Pbe acb 6

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.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

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.

Unlock now