SwiftUI Views Quick Start
SwiftUI Views Quick Start
17 SwiftUI Views
S
iO
Quick Start
Mark Moeykens
www.bigmountainstudio.com FREE SAMPLE
1 Big Mountain Studio
Version: 27-FEBRUARY-2024
©2024 Big Mountain Studio LLC - All Rights Reserved
www.bigmountainstudio.com 2
Special Thanks from Big Mountain Studio
As a new member of Big Mountain Studio you now get 10% off all of our SwiftUI books!
3
Are you new to Swift and SwiftUI?
4
Book Quick Links
www.bigmountainstudio.com 5
HOW TO USE
This is a visual REFERENCE GUIDE. Find a screenshot of something you
want to learn more about or produce in your app and then read it and look
at the code.
Read what is on the screenshots to learn more about the views and what
they can do.
You can also read the book from beginning to end. The choice is yours.
6
Conventions
CONVENTIONS
www.bigmountainstudio.com 7
Conventions
Embedded Videos
www.bigmountainstudio.com 8
Conventions
Custom Code Color Theme
I created a code color theme based off of another color theme called “Gruvbox”.
If you like this color theme and would like to use it in Xcode then you can find it on my GitHub as a gist here.
www.bigmountainstudio.com 9
SWIFTUI
10
Basic Concepts
Basic Concepts
If you are absolutely new to SwiftUI, you should definitely read through this chapter to establish some basic concepts that
you can think with.
www.bigmountainstudio.com 11
Basic Concepts
View
Modifiers:
• Title text size
• Gray text color
View
Modifiers:
• Title text size
• Orange background color
View • Stretched to fit device width
Modifiers:
• Title text size
• White text color
• Orange background
color
• Rounded corners
• Shadow
www.bigmountainstudio.com 12
Basic Concepts
Stacks are views too. They are views that can have
modifiers applied to them.
www.bigmountainstudio.com 13
Basic Concepts
www.bigmountainstudio.com 14
Basic Concepts
www.bigmountainstudio.com 15
Basic Concepts
www.bigmountainstudio.com 16
Basic Concepts
Layout Examples
Now that you know these layout stacks, you can start to guess
how views like these might be arranged using SwiftUI.
VStack
HStack
www.bigmountainstudio.com 17
Basic Concepts
www.bigmountainstudio.com 18
Basic Concepts
www.bigmountainstudio.com 19
Understanding the Syntax
If you have used Swift in the past, then the SwiftUI syntax may look a little different.
It may not be readily apparent just how this code can even compile. This chapter is to help you understand how the code is
able to work.
www.bigmountainstudio.com 20
Understanding the Syntax
var body:
See next some
page View {
www.bigmountainstudio.com 21
’
Understanding the Syntax
www.bigmountainstudio.com 22
Understanding the Syntax
The View
struct BasicSyntax: View {
❓
Views in SwiftUI are structs that conform to
the View protocol. If “body” is a property, then where is the “get”
and “return” syntax?
There is just one property to implement, In Swift, these are optional under certain
the body property. circumstances.
This is where you design your screens. If not needed, they are usually not used to keep
the code clean or simpler.
www.bigmountainstudio.com 23
Understanding the Syntax
Property Getters
Properties can have a getter and setter. But when a struct Person {
// Computed read-only property (no setter, value is not stored)
property has no setter, it s called a “read-only”
var personType: String {
property. get {
And when the property does not store a value, it is return “human"
called a “computed” property. }
}
This is because the value is computed or generated
}
every time the property is read.
In this example, personType is a computed read-only
property.
www.bigmountainstudio.com 24
’
Understanding the Syntax
Since these property changes are optional, you can, for example, write the previous SwiftUI syntax
with a get and return inside the body property. This might look more familiar to you now:
get {
Looking at this code again, you notice the some keyword here.
Normally, when defining a type for a property, you wouldn t see this word.
www.bigmountainstudio.com 25
’
Understanding the Syntax
Opaque Types
struct BasicSyntax: View {
The View returned from the body property is called an
var body: some View { “Opaque Type”.
❓
What exactly is an opaque type?
Well, the English definition for the word “opaque”, when referring to languages, means “hard or
impossible to understand.”
In the code example, it is “hard or impossible to understand” which type of view is being returned but
at least you know it is a view.
When this View (BasicSyntax) is used by iOS to draw the screen, it doesn t have to know that the type
Text is being returned. It is OK with just knowing that some View is being returned and can use that
view to draw the screen.
And so you can return anything in that body property as long as it conforms to the View protocol.
For more information on Opaque Types, I recommend referring to the Swift Programming Language
documentation.
www.bigmountainstudio.com 26
’
Understanding the Syntax
You know there are books inside, but you don t know exactly which
books they are. You can t see the titles of the books.
It hides the details of what is inside, but you know they are books and
you can do things with them, like put them on the book shelf.
Box of Views
In this case, you have a box of different views.
Some Views
www.bigmountainstudio.com 27
’
’
’
’
Understanding the Syntax
// ERROR: Function declares an opaque return type, but the return statements
in its body do not have matching underlying types
if isYellow {
return Color.yellow // Color type does not match the Text type
}
return Text("No color yellow") // Text type does not match the color type
}
}
The body property returns a Color and a Text type. This violates the
❌ some keyword.
www.bigmountainstudio.com 28
Understanding the Syntax
if isYellow { ✅
return Color.yellow
}
Now, the body property always returns a Color type.
return Color.clear This satisfies the some keyword.
}
}
www.bigmountainstudio.com 29
Understanding the Syntax
View Containers
struct Example: View {
var body: some View {
VStack {
💡
Text("Hello World!")
Text("This Vertical Stack is using a function builder") Note: If you don t specify
} a VStack here, SwiftUI will
}
use one by default.
}
So far, you have learned that body is a computed read-only property and can only return ONE object
that is some View. What if you want to show multiple views though?
You learned earlier about the concept of “container” views. These are views that can contain other
views. Remember, the body property can only return one view. You will get an error if you try to return
more than one view in the body property.
In the example above, the VStack (Vertical Stack) is that one view being returned. And that vertical
stack is a container with two more views inside of it.
The VStack is using a “trailing closure,” which just means that it is a code block that is passed into the
initializer to be run by the VStack. You have probably seen this before in Swift, this is not new.
What is new in Swift is the ability to create multiple, new views within the constructor like this. Before
we get into this though, let s better understand how this constructor works.
www.bigmountainstudio.com 30
’
’
Understanding the Syntax
This change may start looking more familiar to you. // Change 1 - Add parentheses and parameter name
struct Example: View {
var body: some View {
VStack(content: {
❓ Text("Hello World!")
Text("This Vertical Stack is using a function builder")
})
How does the VStack know how to accept the }
multiple views like this? }
This is new in Swift. To better understand this, take
a look at the VStack s initializer.
www.bigmountainstudio.com 31
’
’
’
Understanding the Syntax
❓
Text("View 6") views.
Text("View 7")
Text("View 8")
Text("View 9")
How many child views can I build within a Text("View 10")
Text("View 11") // Will no longer cause an error
closure? }
Before iOS 17 there was a limit of 10 views. With }
iOS 17, there is no longer a limit. }
❓ Text("View 6")
Text("View 7")
Text("View 8")
Text("View 9")
What if I need to support iOS 16 or prior? VStack {
Then you will be limited to 10 views. Text("View 10")
You can workaround this by nesting more Text("View 11")
}
views though. Take a look at this example.
}
}
}
www.bigmountainstudio.com 32
My Template
If you are completely new to SwiftUI you may wonder what a lot of this code means right at the beginning of the book. I
have “templates” that contains a title, subtitle and a short description on most SwiftUI screens.
I will take you through step-by-step on how I build this template that I use throughout the book. I will describe each one
only briefly because each modifier I apply to the views here are described in more detail throughout the book within their
own sections.
www.bigmountainstudio.com 33
My Template
My Basic Template
Here is my basic template I use throughout the book to explain views and modifiers.
In the next pages I m going to explain how this is built in SwiftUI. I want to make sure you understand
these parts because you will see them everywhere in this book.
I want to remove any confusion right at the beginning so it doesn t get in your way to learning the
topics in the book.
www.bigmountainstudio.com 34
’
’
My Template
Here, you have a Text view. You want to make it larger so you use the font modifier so you can set the
size to a SwiftUI preset size called largeTitle (this is the largest preset size).
There are more ways you can change the size of text that are covered in this book in the Control Views
chapter, in the section called Text.
www.bigmountainstudio.com 35
My Template
Add a VStack
struct AddVStack: View {
var body: some View {
// Only one view can be returned from the body property.
// Add 20 points between views within this container.
VStack(spacing: 20) { // VStack is a container view that can hold many views
Text("Title")
.font(.largeTitle)
}
}
}
VStack Spacing
The body property can only return one view.
The VStack has an optional parameter you can
You will get an error if you have two views.
use in its initializer to specify how many points
of spacing you want in between views. (Note:
So, you need to use a container view that will
spacing does not add spacing to the top or
contain multiple views. The vertical stack
bottom of the VStack.)
(VStack) is the perfect choice here.
Now you can add more views to the VStack Now, let s add the subtitle
and it will arrange them vertically.
text.
www.bigmountainstudio.com 36
’
My Template
Text("Subtitle")
.font(.title) // Set to be the second largest font.
.foregroundColor(Color.gray) // Change text color to gray.
}
}
}
Subtitle
The subtitle is another text view. This time, you set the size to be the second largest preset size with
the title parameter.
Finally, you modify the view to change the text color to gray. (Note: instead of using Color.gray you
can also use just .gray.)
www.bigmountainstudio.com 37
’
My Template
Text("Subtitle")
.font(.title)
.foregroundColor(.gray)
With the description text view, you are now familiar with the font and foregroundColor modifiers. But now
you want to add a color behind the text. So you use the background modifier to set a color.
The important thing to notice here is it is not a backgroundColor modifier. That does not exist. It is a
background modifier because it adds a layer behind the view.
Color.blue is actually a view. So the background modifier is adding a blue view on a layer behind the text.
We want this view to extend to the edges of the screen. So let’s add that next.
www.bigmountainstudio.com 38
My Template
Text("Subtitle")
.font(.title)
.foregroundColor(.gray)
To extend the text to the edges of the device, we use the frame modifier. You don t need to set a fixed
value. Instead, you can just modify the text view and say its frame s maximum width can extend to
infinity until it hits its parent s frame and then will stop. Its parent s frame is the VStack.
This is looking good. It would look better though if there was more space around the text that pushed
out the blue background.
www.bigmountainstudio.com 39
’
’
’
’
My Template
Text("Subtitle")
.font(.title)
.foregroundColor(.gray)
Padding
Use the padding modifier to add space around a view. Remember, the order of modifiers matter. You
can add the padding modifier anywhere as long as it is BEFORE the background modifier. If it was after
the background, it would add space around the blue background. We want the space between the text
and the background.
www.bigmountainstudio.com 40
My Template
Version 2
When I updated the book with SwiftUI 2, I wanted a more efficient way of adding a title, subtitle and
description.
So I made my own view, called HeaderView, where I can pass in the information and it will format it.
If you're interested in how this is done, look in the Xcode project that comes with the paid book bundle
for the file “HeaderView.swift”.
www.bigmountainstudio.com 41
SwiftUI Basics
Now that you understand this basic template I use for demonstrating topics, I will start using it. Be sure to read what is on
each screenshot (or find the text in the code to read).
www.bigmountainstudio.com 42
Scope and Overriding
struct ScopeAndOverriding: View {
var body: some View { ❓
VStack(spacing: 20) {
Text("Refactoring") Why isn't the first Text view affected?
.font(.largeTitle) This Text view has its own font modifier.
This means it overrides the parent s font
modifier.
Text("Reusing Modifiers")
.font(.title)
.foregroundStyle(Color.gray)
www.bigmountainstudio.com 43
’
Short Introduction to Symbols
struct SymbolsIntro: View {
var body: some View {
VStack(spacing: 20) {
Text("Images")
.font(.largeTitle)
Text("Using SF Symbols")
.foregroundColor(.gray)
Text("You will see I use icons or symbols to add clarity to what I'm demonstrating.
These come from Apple's new symbol font library which you can browse using an
app called 'SF Symbols'.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(Color.white)
Even though an Image view is used to initialize a symbol, you use the font modifier to change its size.
These symbols actually come from fonts. So use font modifiers to change them. There is a whole
section that covers this. Go here to download and install the SF Symbols app.
www.bigmountainstudio.com 44
Layers
VStack(spacing: 40) {
Text("Layers")
.font(.largeTitle)
Text("The Basics")
.foregroundColor(.gray)
Text("With SwiftUI views, you can add layers on top (.overlay) and behind (.background) the
view.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(Color.white)
Image("Layers")
}
.font(.title)
I use layers (background and overlay) early in the book so I want to make sure you understand this
concept.
www.bigmountainstudio.com 45
Short Introduction to Shapes
struct Shapes: View {
var body: some View {
VStack(spacing: 15) {
Text("Shapes")
.font(.largeTitle)
Text("Short Introduction")
.foregroundStyle(Color.gray)
Text("I'll make shapes, give them color and put them behind other views just for
decoration.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue) RoundedRectangle is a common
.foregroundStyle(Color.white) shape.
www.bigmountainstudio.com 46
Layout Behavior
In SwiftUI, you may wonder why some views layout differently than others. You can observe two behaviors when it comes to
the size and layout of views:
1. Some views pull in to be as small as possible to fit their content. (I will refer to these as “pull-in” views.)
2. Some views push out to fill all available space. (I will refer to these as “push-out” views.)
Knowing these two behaviors can help you predict what will happen when using the different views.
www.bigmountainstudio.com 47
Layout Behavior
Image(systemName: "arrow.down.to.line.alt")
Image(systemName: "arrow.up.to.line.alt")
www.bigmountainstudio.com 48
Layout Behavior
www.bigmountainstudio.com 49
SEE YOUR WORK
50
Preview Options
As you practice these examples, you might want to see your SwiftUI working on different devices in different modes, including light or dark
mode or with different accessibility settings.
You can do all of this without even having to launch the Simulator.
When using SwiftUI, you get a preview canvas that will show you how your views will render.
www.bigmountainstudio.com 51
Preview Options
www.bigmountainstudio.com 52
Preview Options
Introduction
struct Previews_Intro: View {
var body: some View {
VStack(spacing: 20) {
Text("Previews")
.font(.largeTitle)
Text("Introduction")
.foregroundColor(.gray)
Text("Xcode looks for a struct that conforms to the PreviewProvider protocol and
accesses its previews property to display a view on the Canvas.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.red)
.foregroundColor(.white)
}.font(.title)
}
}
www.bigmountainstudio.com 53
Preview Options
#Preview iOS 17
www.bigmountainstudio.com 54
’
Preview Options
Dark Mode
struct Preview_DarkMode: View {
var body: some View {
VStack(spacing: 20) {
Text("Previews").font(.largeTitle)
Text("Dark Mode").foregroundStyle(.gray)
Text("By default, your preview will show in light mode. To see it in
dark mode, you can use the environment modifier.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.red)
.foregroundStyle(.white)
}.font(.title)
}
}
#Preview {
Preview_DarkMode()
.preferredColorScheme(.dark)
}
www.bigmountainstudio.com 55
Preview Options
www.bigmountainstudio.com 56
Preview Options
Changing Devices
www.bigmountainstudio.com 57
Preview Options
www.bigmountainstudio.com 58
Preview Options
Orientation Variants
www.bigmountainstudio.com 59
’
Preview Options
💡
Note: The changes you make in the
Canvas Device Settings will apply to ALL
canvases.
www.bigmountainstudio.com 60
Preview Options
Environment Overrides
If you prefer to see your work in the Simulator then you can access many of the options
mentioned through the Environment Overrides options.
This button will show up when you run your app in the debugging toolbar at the bottom
of Xcode.
www.bigmountainstudio.com 61
LAYOUT VIEWS
62
Layout Views
VStack GeometryReader
LazyVStack LazyHGrid
HStack LazyVGrid
LazyHStack ScrollViewReader
Grid Table
Spacer ViewThatFits
VStack stands for “Vertical Stack”. It is a pull-in container view in which you pass in up to ten views and it will compose
them one below the next, going down the screen.
www.bigmountainstudio.com 64
VStack
Introduction
struct VStack_Intro : View {
var body: some View {
VStack(spacing: 20) {
HeaderView("VStack",
subtitle: "Introduction",
desc: "A VStack will vertically arrange other views within it.",
back: .blue, textColor: .white)
Text("View 1")
Text("View 2")
Text("View 3")
Text("View 4")
Text("View 5")
Text("View 6")
Text("View 7")
Text("View 8")
Text("View 9")
}
.font(.title)
}
}
www.bigmountainstudio.com 65
VStack
Spacing
VStack(spacing: 80) { Set spacing in the initializer.
Text("VStack")
.font(.largeTitle)
Text("Spacing")
.font(.title)
.foregroundColor(.gray)
Text("The VStack initializer allows you to set the spacing between all the views inside the
VStack")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue).font(.title)
.foregroundColor(.white)
Image(systemName: "arrow.up.and.down.circle.fill")
.font(.largeTitle)
www.bigmountainstudio.com 66
VStack
Alignment
VStack(spacing: 20) {
Text("VStack")
.font(.largeTitle)
Text("Alignment")
.font(.title)
.foregroundColor(.gray)
Text("By default, views in a VStack are center aligned.")
...
www.bigmountainstudio.com 67
This book is a preview of:
Over 1,000 pages of SwiftUI Find out how to implement action sheets, modals, popovers
Over 700 screenshots and video showing you what you can and custom popups
do so you can quickly come back and reference the code Master all the layout modifiers including background and
Learn all the ways to work with and modify images overlay layers, scaling, offsets padding and positioning
See the many ways you can use color as views How do you hide the status bar in SwiftUI? Find out!
Discover the different gradients and how you can apply them This is just the tip of the mountain!
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 68
iOS 14
LazyVStack
www.bigmountainstudio.com 69
’
HStack
HStack stands for “Horizontal Stack”. It is a pull-in container view in which you pass in up to ten views and it will compose
them side-by-side.
www.bigmountainstudio.com 70
HStack
Introduction
struct HStack_Intro: View {
var body: some View {
VStack(spacing: 40) {
HeaderView("HStack",
subtitle: "Introduction",
desc: "An HStack will horizontally arrange other views within it.",
back: .orange)
HStack {
Text("View 1")
Text("View 2")
Text("View 3")
}
}
.font(.title)
}
}
www.bigmountainstudio.com 71
HStack
Spacing
VStack(spacing: 40) {
Text("HStack")
.font(.largeTitle)
Text("Spacing")
.font(.title)
.foregroundColor(.gray)
Text("The HStack initializer allows you to set the spacing between all the views inside the
HStack")
.frame(maxWidth: .infinity)
.padding()
.background(Color.orange).font(.title)
.foregroundColor(.black)
Text("Default Spacing")
.font(.title)
HStack {
Image(systemName: "1.circle")
Image(systemName: "2.circle")
Image(systemName: "3.circle")
}.font(.largeTitle)
Divider()
Text("Spacing: 100")
.font(.title)
HStack(spacing: 100) { Set spacing in the initializer.
Image(systemName: "1.circle")
Image(systemName: "2.circle")
Image(systemName: "3.circle")
}.font(.largeTitle)
}
www.bigmountainstudio.com 72
HStack
Alignment
Text("By default, views within an HStack are vertically aligned in the center.")
...
HStack {
Rectangle().foregroundColor(.orange).frame(width: 25)
Text("Leading")
Spacer()
Text("Center")
Spacer()
Text("Trailing")
.padding(.trailing)
Set alignment in the initializer.
}
.border(Color.orange)
HStack(alignment: .top) {
Rectangle().foregroundColor(.orange).frame(width: 25)
Text("Leading")
Spacer()
Text("Top")
Spacer()
Text("Trailing")
.padding(.trailing)
}
.border(Color.orange)
HStack(alignment: .bottom) {
Rectangle().foregroundColor(.orange).frame(width: 25)
Text("Leading")
Spacer()
Text("Bottom")
Spacer()
Text("Trailing")
.padding(.trailing)
}
.border(Color.orange)
www.bigmountainstudio.com 73
HStack
Text Alignment
struct HStack_TextAlignment: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("HStack",
subtitle: "Text Alignment",
desc: "HStacks have another alignment option to help better align the
bottom of text.",
back: .orange)
HStack(alignment: .bottom) {
Text("Hello")
Text("amazing")
.font(.largeTitle)
Text(“developer!")
}
.font(.body)
DescView(desc: "Notice the bottom of the text isn't really aligned above. Use
firstTextBaseline or lastTextBaseline instead:", back: .orange)
HStack(alignment: .firstTextBaseline) {
Text("Hello")
Text("amazing")
.font(.largeTitle)
Text("developer!")
This will align the text normally.
}
But what s the difference between first and
.font(.body)
} last text baseline? See on the next page.
.font(.title)
}
}
www.bigmountainstudio.com 74
’
HStack
HStack(alignment: .firstTextBaseline) {
Text("Amazing developer")
.font(.title3)
Text("Really amazing developer")
}
.frame(width: 250)
DescView(desc: "The lastTextBaseline will align the bottom of the text on the last
lines (\"developer\" and \"developer\").", back: .orange)
HStack(alignment: .lastTextBaseline) {
Text("Amazing developer")
.font(.title3)
Text("Really amazing developer")
}
.frame(width: 250)
}
.font(.title)
}
}
www.bigmountainstudio.com 75
HStack
Customization
struct HStack_Customizing : View {
var body: some View {
VStack(spacing: 20) {
HeaderView("HStack",
subtitle: "Customizing",
desc: "HStacks are views that can have modifiers applied to them just
like any other view.",
back: .orange)
HStack {
Text("Leading")
Text("Middle")
Text("Trailing")
}
.padding()
.border(Color.orange) // Create a 2 point border using the color specified
HStack(spacing: 10) {
Image(systemName: "1.circle")
Image(systemName: "2.circle")
Image(systemName: "3.circle")
}.padding()
HStack(spacing: 20) {
Image(systemName: "a.circle.fill")
Image(systemName: "b.circle.fill")
Image(systemName: "c.circle.fill")
Image(systemName: "d.circle.fill")
Image(systemName: "e.circle.fill")
}
.font(.largeTitle).padding()
.background(RoundedRectangle(cornerRadius: 10)
.foregroundColor(.orange))
}
.font(.title)
}
}
www.bigmountainstudio.com 76
HStack
Layout Priority
When using a horizontal stack with text views within it, there s a chance that text might truncate if
you are not allowing them to wrap. In this case, you can prioritize which one will truncate last with
layout priority. The default value is 0. The higher the number, the higher the priority to have enough
space to not be truncated.
HStack {
Text("SwiftUI")
.font(.largeTitle).lineLimit(1) // Don't let text wrap
Image("SwiftUI")
.resizable()
.frame(width: 80, height: 80)
Text("Brings Balance")
.font(.largeTitle)
.layoutPriority(1) // Truncate last
}
.padding([.horizontal])
Divider()
HStack {
Text("SwiftUI")
.font(.largeTitle)
.layoutPriority(1) // Truncate last
Image("SwiftUI")
.resizable()
.frame(width: 80, height: 80)
Text("Brings Balance") Note: You can learn more
.font(.largeTitle).lineLimit(1) // Don't let text wrap about layout priority in the
} chapter “Layout Modifiers”,
.padding(.horizontal) section “LayoutPriority”.
www.bigmountainstudio.com 77
’
iOS 14
LazyHStack
www.bigmountainstudio.com 78
’
Depth (Z) Stack
A Depth Stack (ZStack) is a pull-in container view. It is a view that overlays its child views on top of each other. (“Z”
represents the Z-axis which is depth-based in a 3D space.)
You learned earlier about creating layers with the background and overlay modifiers. ZStack is another way to create layers
with views that control their own sizing and spacing.
So, the ZStack is a pull-in container view but you may think it is a push-out view because of the first example but it s
actually the color that is pushing out.
www.bigmountainstudio.com 79
’
ZStack
Introduction
ZStack {
// LAYER 1: Furthest back
You set depth by the order of
Color.gray // Yes, Color is a view! the views inside the ZStack.
Text("Introduction")
.foregroundColor(.white)
Text("But notice the Color stops at the Safe Areas (white areas on top and bottom).")
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
}
.font(.title)
}
www.bigmountainstudio.com 80
ZStack
VStack(spacing: 20) {
Text("ZStack")
.font(.largeTitle)
Text("Ignoring the Safe Areas will extend a view to fill the whole scene.")
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(Color.green)
}
.font(.title)
}
.ignoresSafeArea(.all) // Ignore the safe areas
Learn more about what Safe Areas are and ways to ignore edges in the chapter “Layout Modifiers” in the
section “Ignores Safe Area”.
www.bigmountainstudio.com 81
ZStack
Background Problem
struct ZStack_BackgroundColor_Problem: View {
var body: some View {
ZStack {
Color.gray
VStack(spacing: 20) {
Text("ZStack") // This view is under the notch
.font(.largeTitle)
Text("Having the ZStack edges ignoring the safe area edges might be a mistake.
\nYou notice that the top Text view is completely under the notch.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
www.bigmountainstudio.com 82
ZStack
Background Solution
struct ZStack_BackgroundColor_Solution: View {
var body: some View {
ZStack {
Color.gray
.ignoresSafeArea() // Have JUST the color ignore the safe areas edges, not
the VStack.
VStack(spacing: 20) {
Text("ZStack")
.font(.largeTitle)
Text("To solve the problem, you want just the color (bottom layer) to ignore
the safe area edges and fill the screen. Other layers above it will stay
within the Safe Area.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
Spacer()
}
.font(.title)
}
}
}
www.bigmountainstudio.com 83
ZStack
Layering
struct ZStack_Layering: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("ZStack",
subtitle: "Layering & Aligning",
desc: "ZStacks are great for layering views. For example, putting text on
top of an image.", back: .green, textColor: .white)
ZStack {
Image("yosemite_large")
.resizable() // Allows image to change size
.scaledToFit() // Keeps image the same aspect ratio when resizing
Rectangle()
.fill(Color.white.opacity(0.6))
.frame(maxWidth: .infinity, maxHeight: 50)
DescView(desc: "But what if you wanted to have all the views align to the bottom?”,
back: .green, textColor: .white)
}
.font(.title)
}
}
www.bigmountainstudio.com 84
ZStack
Aligning
struct ZStack_Aligning: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("ZStack",
subtitle: "Aligning",
desc: "The ZStack allows you to align all the views within it.",
back: .green, textColor: .white)
ZStack(alignment: .topLeading) {
Use the alignment parameter
Image("yosemite_large")
in the ZStack s initializer to
.resizable()
set where you want all views
.aspectRatio(contentMode: .fit)
within to be aligned.
Rectangle()
.fill(Color.white.opacity(0.6))
.frame(maxWidth: .infinity, maxHeight: 60)
ZStack(alignment: .bottomTrailing) {
Image("yosemite_large")
.resizable()
.aspectRatio(contentMode: .fit)
www.bigmountainstudio.com 85
’
ZStack
Rectangle()
.fill(Color.white.opacity(0.6))
.frame(maxWidth: .infinity, maxHeight: 60)
Alignment Choices
Text("Yosemite National Park")
• center
.font(.title)
.padding() • leading
} • trailing
}
.font(.title) • top
}
• bottom
}
• topLeading
• topTrailing
• bottomLeading
• bottomTrailing
www.bigmountainstudio.com 86
Grid
iOS 16
Grid
SAVE
Grids are pull-in views, they only take 10%
up asAND
muchUNLOCK THE contents.
space as their BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 87
Spacer
You may notice that when you add new pull-in views, such as Text views, they appear in the center of the screen. You can
use the Spacer to push these views apart, away from the center of the screen.
www.bigmountainstudio.com 88
Spacer
Introduction
VStack {
Text("Spacer")
.font(.largeTitle)
Text("Introduction")
.foregroundColor(.gray)
Image(systemName: "arrow.up.circle.fill")
Image(systemName: "arrow.down.circle.fill")
HStack {
Text("Horizontal Spacer")
Image(systemName: "arrow.left.circle.fill")
Image(systemName: "arrow.right.circle.fill")
}
.padding(.horizontal)
Color.yellow
.frame(maxHeight: 50) // Height can decrease but not go higher than 50
}
.font(.title) // Apply this font to every view within the VStack
www.bigmountainstudio.com 89
Spacer
Evenly Spaced
Text("Use Spacer to evenly space views horizontally so they look good on any
device.")
...
Text("After")
...
HStack {
Spacer()
VStack(alignment: .leading) {
Text("Names")
.font(.largeTitle)
.underline()
Text("Chase")
Text("Rodrigo")
Text("Mark")
Text("Evans")
}
Spacer()
VStack(alignment: .leading) {
Text("Color")
.font(.largeTitle)
.underline()
Text("Red")
Text("Orange")
Text("Green")
Text("Blue")
}
Spacer()
}
www.bigmountainstudio.com 90
Spacer
Minimum Length
VStack(spacing: 10) {
Text("Spacer")
.font(.largeTitle)
Text("Minimum Length")
.font(.title)
.foregroundColor(.gray)
Text("You can set a minimum space to exist between views using the minLength modifier on the
Spacer.")
...
Text("No minLength set (system default is used)")
.bold()
HStack {
Image("yosemite")
Spacer()
Text("This is Yosemite National Park").lineLimit(1)
}.padding()
Text("minLength = 0")
Set the minimum length in the
.bold()
HStack { Spacer s initializer.
Image("yosemite")
Spacer(minLength: 0)
Text("This is Yosemite National Park").lineLimit(1)
}.padding()
Text("minLength = 20")
.bold()
HStack {
Image("yosemite")
Spacer(minLength: 20)
Text("This is Yosemite National Park").lineLimit(1)
}.padding()
}
www.bigmountainstudio.com 91
’
Spacer
VStack(spacing: 5) {
Spacer()
.frame(width: 5) Spacers are views and can be
.background(Color.blue) modified like views.
Text("33% Down")
Spacer()
.frame(width: 5)
.background(Color.blue)
Spacer()
.frame(width: 5)
.background(Color.blue)
}
VStack(spacing: 5) {
Spacer()
.frame(width: 5)
.background(Color.blue)
Spacer()
www.bigmountainstudio.com 92
Spacer
.frame(width: 5)
.background(Color.blue)
Spacer()
.frame(width: 5) Note: You can also use Spacers horizontally to place
.background(Color.blue)
views a percentage from the leading or trailing sides
Text("75% Down")
of the screen.
Spacer()
.frame(width: 5)
.background(Color.blue)
}
}
}.font(.title)
}
}
www.bigmountainstudio.com 93
GeometryReader
It is difficult, if not impossible, to get the size of a view. This is where the GeometryReader can help.
The GeometryReader is similar to a push-out container view in that you can add child views to it. It will allow you to inspect
and use properties that can help with positioning other views within it. You can access properties like height, width and safe
area insets which can help you dynamically set the sizes of views within it so they look good on any size device.
www.bigmountainstudio.com 94
Geometry Reader
Introduction
struct GeometryReader_Intro : View {
var body: some View {
VStack(spacing: 20) {
HeaderView("GeometryReader", subtitle: "Introduction", desc: "GeometryReader is a
container view that pushes out to fill up all available space. You use it to help with
positioning items within it.",
back: .clear)
GeometryReader { _ in
In SwiftUI, when you see the word
// No child views inside
“geometry”, think size and position.
}
.background(Color.pink)
}
.font(.title)
}
}
www.bigmountainstudio.com 95
Geometry Reader
Alignment
struct GeometryReader_Alignment: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("GeometryReader", subtitle: "Alignment", desc: "Child views within the
GeometryReader are aligned in the upper left corner by default.", back: .clear)
GeometryReader {_ in
Image(systemName: "arrow.up.left")
Notice that there is no alignment or
.padding()
positioning specified on the image.
}
.background(Color.pink)
}
.font(.title)
}
}
www.bigmountainstudio.com 96
Geometry Reader
Layers
struct GeometryReader_Layers: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("GeometryReader", subtitle: "Layers", desc: "The child views within a
GeometryReader will stack on top of each other, much like a ZStack.",
back: .clear)
GeometryReader {_ in
Image(systemName: "18.circle")
Note, I wouldn t recommend using a
.padding() GeometryReader in place of a
Image(systemName: "20.square") ZStack.
.padding()
Image(systemName: "50.circle") ZStack provides convenient
.padding() alignment options for layout that
} GeometryReader does not.
.font(.largeTitle)
.foregroundColor(.white)
.background(Color.pink)
}
.font(.title)
}
}
www.bigmountainstudio.com 97
’
Geometry Reader
Getting Size
struct GeometryReader_GettingSize : View {
var body: some View {
VStack(spacing: 10) {
HeaderView("GeometryReader", subtitle: "Getting Size", desc: "Use the geometry
reader when you need to get the height and/or width of a space.",
back: .clear)
www.bigmountainstudio.com 98
’
’
Geometry Reader
Positioning
struct GeometryReader_Positioning: View {
var body: some View {
VStack(spacing: 20) {
Text("GeometryReader").font(.largeTitle)
Text("Positioning").font(.title).foregroundColor(.gray)
Text("Use the GeometryProxy input parameter to help position child views at
different locations within the geometry's view.")
.font(.title)
.padding()
GeometryReader { geometryProxy in
Text("Upper Left")
.font(.title)
.position(x: geometryProxy.size.width/5,
y: geometryProxy.size.height/10)
Text("Lower Right")
.font(.title)
.position(x: geometryProxy.size.width - 90,
y: geometryProxy.size.height - 40)
}
.background(Color.pink)
.foregroundColor(.white)
Text("Note: The position modifier uses the view's center point when setting the X
and Y parameters.")
.font(.title)
}
}
}
www.bigmountainstudio.com 99
Geometry Reader
Getting Coordinates
struct GeometryReader_GettingCoordinates : View {
var body: some View {
VStack(spacing: 10) {
HeaderView("GeometryReader", subtitle: "Getting Coordinates", desc: "Getting the
coordinates (x, y) of a geometry view is little different. Take a look at this example:",
back: .clear)
GeometryReader { geometryProxy in
VStack(spacing: 10) {
Text("X: \(geometryProxy.frame(in: CoordinateSpace.local).origin.x)")
Text("Y: \(geometryProxy.frame(in: CoordinateSpace.local).origin.y)")
}
.foregroundColor(.white)
}
.background(Color.pink)
www.bigmountainstudio.com 100
’
’
Geometry Reader
GeometryReader { geometry in
VStack(alignment: .leading, spacing: 20) {
Text("Local Coordinate Space")
HStack(spacing: 10) {
// I'm converting to Int just so we don't have so many zeros
Text("minX: \(Int(geometry.frame(in: .local).minX))")
Spacer()
Text("midX: \(Int(geometry.frame(in: .local).midX))")
Spacer()
Text("maxX: \(Int(geometry.frame(in: .local).maxX))")
}
Text("Global Coordinate Space")
HStack(spacing: 10) {
// I'm converting to Int just so we don't have so many zeros
Text("minX: \(Int(geometry.frame(in: .global).minX))")
Spacer()
Text("midX: \(Int(geometry.frame(in: .global).midX))")
Spacer()
Text("maxX: \(Int(geometry.frame(in: .global).maxX))")
}
}.padding(.horizontal)
}
www.bigmountainstudio.com 101
Geometry Reader
HStack {
GeometryReader { geometry in
VStack(spacing: 10) {
Text("minY: \(Int(geometry.frame(in: .global).minY))")
Spacer()
Text("midY: \(Int(geometry.frame(in: .global).midY))")
Spacer()
Text("maxY: \(Int(geometry.frame(in: .global).maxY))")
}.padding(.vertical)
}
.foregroundColor(.white)
.background(Color.pink)
Image("MinMidMax")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
.font(.title)
.padding()
}
} Notice how the min, mid and max values change as the
geometry reader adapts to different device sizes.
www.bigmountainstudio.com 102
Geometry Reader
HeaderView("GeometryReader", subtitle: "SafeAreaInsets", desc: "GeometryReader can also tell you the safe area insets it has.",
back: .clear)
GeometryReader { geometryProxy in
VStack {
Text("geometryProxy.safeAreaInsets.leading: \(geometryProxy.safeAreaInsets.leading)")
Text("geometryProxy.safeAreaInsets.trailing: \(geometryProxy.safeAreaInsets.trailing)")
Text("geometryProxy.safeAreaInsets.top: \(geometryProxy.safeAreaInsets.top)")
Text("geometryProxy.safeAreaInsets.bottom: \(geometryProxy.safeAreaInsets.bottom)")
}
.padding()
}
.background(Color.pink)
.foregroundColor(.white)
www.bigmountainstudio.com 103
iOS 14
LazyHGrid
www.bigmountainstudio.com 104
iOS 14
LazyVGrid
105
ScrollViewReader
iOS 14
ScrollViewReader
www.bigmountainstudio.com 106
iOS 15
ControlGroup
Use the ControlGroup to put similar types of controls together, such as buttons. In my opinion, the use of this seems
limited.
ControlGroup {
Button("Hello!") { }
Button(action: {}) {
Image(systemName: "gearshape.fill")
}
}
}
Image(systemName: "gearshape.fill") 💡
}
.controlGroupStyle(.navigation) Note: You may ask yourself
} when you would use this.
.font(.title)
} I think it makes more sense
} inside of toolbars as well as
on macOS.
Table
iOS 16
Table
SAVE
In iOS though you will only see one 10% AND
column. UNLOCK
So it will appear THE BOOK
just like TODAY
a List view. FOR ONLY $55 $49.50!
www.bigmountainstudio.com 109
iOS 16
ViewThatFits
ViewThatFits is a very unique container that can contain multiple views but will only draw one of the views. That s right, it will only draw the
view that fits the space it is given. This SwiftUI chapter is locked in this
preview.
You specify the larger view first and then progressively smaller views after that. The first view s size will be evaluated and if it can t fit in the
given space, then the next view s size will be evaluated and so on.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
If none of the views fit, the last view is chosen.
www.bigmountainstudio.com 110
’
’
’
’
ContentUnavailableView
iOS 17
ContentUnavailableView
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 111
CONTROL VIEWS
112
Chapter Quick Links
Text
Gauge NavigationSplitView SecureField TextEditor
Box
The Button is a pull-in view with a wide range of composition and customization options to be presented to the user. The
button can be just text, just an image or both combined.
www.bigmountainstudio.com 114
Button
Introduction
struct RegularButton : View {
var body: some View {
VStack(spacing: 40) { If you just want to show the default text
Button("Regular Button") { style in a button then you can pass in a
// Code here
string as the first parameter.
} This is the quickest and easiest way to
make a button.
Button {
// Code here
} label: { Use this initializer to customize the
Text("Regular Button") content within the button.
.bold()
}
}
.font(.title) // Make all fonts use the title style
}
}
www.bigmountainstudio.com 115
Button
Text Composition
struct Button_TextModifiers : View {
You can add more than one text view to
var body: some View {
a button and format them separately.
VStack(spacing: 40) {
Button {} label: {
Text("Forgot Password?")
Text("Tap to Recover") Views arranged horizontally by default.
.foregroundStyle(.orange)
}
Button {} label: {
VStack { You can use any layout or
Text("New User") container view you want within
Text("(Register Here)").font(.body) the label content.
}
}
}
.font(.title)
}
}
www.bigmountainstudio.com 116
Button
With Backgrounds
struct Button_WithBackgrounds : View {
var body: some View { You can add various
VStack(spacing: 60) { backgrounds and shadows
Button(action: {}) { to buttons to further
Text("Solid Button") customize them.
.padding()
.foregroundStyle(.white)
.background(Color.purple)
.clipShape(RoundedRectangle(cornerRadius: 16))
💡
}
Button(action: {}) {
Text("Button With Shadow")
.padding(12) Note: It is a good idea to
.foregroundStyle(.white) put your modifiers within
.background(Color.purple) the button instead of on the
.shadow(color: Color.purple, radius: 20, y: 5) button itself. So when the
} button is tapped, the whole
button flashes.
Button(action: {}) {
Text("Button With Rounded Ends")
.padding(EdgeInsets(top: 12, leading: 20, bottom: 12, trailing: 20))
.foregroundStyle(.white)
.background(Color.purple, in: Capsule())
}
You can apply shapes as
}
backgrounds; such as
.font(.title)
Capsule, Rectangle, Circle,
}
and RoundedRectangle.
}
www.bigmountainstudio.com 117
Button
With Borders
struct Button_WithBorders: View {
var body: some View { Here are a couple of options
if you are looking for a way
VStack(spacing: 60) {
to add a border around your
Button(action: {}) {
button.
Text("Square Border Button")
.padding()
.border(Color.purple, width: 2)
}
Button(action: {}) {
Text("Border Button")
.padding()
.background {
RoundedRectangle(cornerRadius: 10)
.stroke(Color.purple, lineWidth: 2)
}
}
}
.font(.title)
}
}
www.bigmountainstudio.com 118
Button
With SF Symbols
struct Button_WithSymbols : View {
var body: some View { You can add SF Symbols to
VStack(spacing: 40) { your buttons with the
Button(action: {}) { Image(systemName:) view.
Text("Button With Symbol")
.padding(.horizontal)
Image(systemName: "gift.fill")
} Or you can use what is
called a Label that groups
Button(action: {}) { texts and an SF Symbol
Label("Search for Wifi", systemImage: "wifi") together.
}
Button(action: {}) {
VStack {
Image(systemName: "video.fill") Or use a layout view to
Text("Record") arrange your text and
.padding(.horizontal) images.
}
.padding()
.foregroundStyle(Color.white)
.background(RoundedRectangle(cornerRadius: 25))
}
}
.tint(.purple)
.font(.title)
For even more ways to customize buttons, see
}
the chapter on Paints where you can learn how
}
to apply the 3 different gradients to them.
www.bigmountainstudio.com 119
Button
With Images
struct Button_WithPhotos: View {
If you are using a photo for the
var body: some View {
button content, it should show
VStack(spacing: 100) { up fine from iOS 15+.
Button(action: {}) {
Image("yosemite")
Button(action: {}) {
Image("yosemite")
If your image has transparency,
.renderingMode(.template)
you can change the
.clipShape(Capsule())
renderingMode to template.
} This allows you to assign the
} template different colors.
Earlier versions of iOS will render
.font(.title)
By default, all buttons use a blue
the image like you see in the last
tint that you can override.
example. }
www.bigmountainstudio.com 120
’
Button
ButtonStyle iOS 15
.buttonStyle(.automatic)
Button("Bordered") { }
.buttonStyle(.bordered)
💡
Button("BorderedProminent") { }
Note: The text here becomes the primary
.buttonStyle(.borderedProminent) color (black for light mode, white for dark
mode). You can always override this with
Button("Borderless") { } the foregroundStyle modifier.
.buttonStyle(.borderless)
Button("Plain") { }
.buttonStyle(.plain)
www.bigmountainstudio.com 121
Button
ControlSize iOS 15
Button("Bordered - Small") { }
.controlSize(.small)
Button("Bordered - Regular") { }
.controlSize(.regular)
Button("Bordered - Large") { }
.controlSize(.large)
Button(action: {}) {
Text("Bordered - Large") You can still change the
.frame(maxWidth: .infinity) size manually and the
} shape will be the same.
.controlSize(.large)
}
.buttonStyle(.bordered)
.tint(.purple)
.font(.title) Notice how the buttonStyle is on the parent
} view and gets applied to all the child views
} that are buttons.
www.bigmountainstudio.com 122
Button
Role iOS 15
Button("Normal") { }
.buttonStyle(.borderedProminent)
.buttonStyle(.bordered)
.controlSize(.large)
.font(.title)
www.bigmountainstudio.com 123
Button
ButtonBorderShape iOS 15
Button("Set Radius") { }
.buttonBorderShape(.roundedRectangle(radius: 24))
} 💡
.buttonStyle(.bordered)
.controlSize(.large) Note: This modifier ONLY works
.font(.title) on buttons that are bordered or
.tint(.purple) borderedProminent.
}
}
www.bigmountainstudio.com 124
Button
Disabled
struct Button_Disabled: View {
Use the disabled modifier to
var body: some View {
prevent the user from interacting
VStack(spacing: 60) {
with buttons.
Button("Enabled") { }
Button("Disabled") { }
.disabled(true)
Button("Enabled") { }
.buttonStyle(.bordered)
Button("Disabled") { }
.buttonStyle(.bordered)
.disabled(true)
Button("Enabled") { }
.buttonStyle(.borderedProminent)
Button("Disabled") { }
.buttonStyle(.borderedProminent)
.disabled(true)
}
.controlSize(.large)
.font(.title)
.tint(.purple)
}
}
www.bigmountainstudio.com 125
Button
www.bigmountainstudio.com 126
Chart
iOS 16
Chart
This is a push-out view. UNLOCK THE BOOK TODAY FOR ONLY $55!
www.bigmountainstudio.com 127
ColorPicker
iOS 14
ColorPicker
!
www.bigmountainstudio.com 128
iOS 14
DatePicker
The date picker provides a way for the user to select a date and time. You bind the selected date to a property. You can
read this property to find out what was selected or set this property for the DatePicker to show the date you want.
(Note: If you have to support the DatePicker for iOS 13, then it will look different from what you see in this chapter.)
www.bigmountainstudio.com 129
DatePicker
Introduction iOS 14
Text("With label:")
}.font(.title)
} What you see here is representative of the compact date picker style
} (text representation of the date).
www.bigmountainstudio.com 130
DatePicker
Styles iOS 14
www.bigmountainstudio.com 131
’
’
DatePicker
💡
}
.font(.title)
}
} Note: The order of the displayed components
does not affect the displayed order. The hour
and minute still come second.
www.bigmountainstudio.com 132
DatePicker
Form {
DatePicker("Today", selection: $date,
displayedComponents: .date)
Section {
Text("Graphical Picker Style:")
DatePicker("Birthday", selection: $date,
displayedComponents: .date)
.datePickerStyle(.graphical)
}
}
}
When the compact style is
.font(.title)
tapped, a pop up shows
}
}
the graphical date picker.
www.bigmountainstudio.com 133
DatePicker
Customizing iOS 14
www.bigmountainstudio.com 134
DatePicker
www.bigmountainstudio.com 135
DisclosureGroup
iOS 14
DisclosureGroup
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 136
Form
The Form view is a great choice when you want to show settings, options, or get some user input. It is easy to set up and
customize as you will see on the following pages.
www.bigmountainstudio.com 137
Form
Introduction
struct Form_Intro : View {
var body: some View {
Form { Forms come with a built-in
Section { scroll view if the contents
Text("This is a Form!") exceed the height of the
.font(.title) screen.
Text("You can put any content in here")
Text("The cells will grow to fit the content")
Text("Remember, it's just views inside of views")
}
Section {
Text("Limitations")
.font(.title)
Text("There are built-in margins that are difficult to get around. Take a look
at the color below so you can see where the margins are:")
Color.purple
}
Section {
Text("Summary")
.font(.title)
Text("Pretty much what you see here is what you get.")
}
}
}
}
www.bigmountainstudio.com 138
Form
www.bigmountainstudio.com 139
Form
Section {
Text("Use increased header prominence to make it stand out more.")
} header: {
Text("Increased Header Prominence")
}
.headerProminence(.increased)
}
}
}
💡
Note: I have found that I can put this
modifier on the Section or the Text
inside the header closure for it to work.
www.bigmountainstudio.com 140
Form
Text("Forms and Lists allow you to set a background view with a function called
\"listRowBackground(view:)\".")
Text("You can use this modifier on just one row, like this.")
.listRowBackground(Color.purple)
.foregroundStyle(.white)
} header: {
Text("Form").font(.largeTitle)
}
Section {
Text("Or you can set a view or color for a whole section.")
Text("Note, the color of the section header is not affected when set on
Section.")
.fixedSize(horizontal: false, vertical: true)
} header: {
Text("Whole Section")
.font(.title).foregroundStyle(.gray)
}
.foregroundStyle(.white)
.listRowBackground(Color.purple)
}
.font(.title2)
}
}
www.bigmountainstudio.com 141
Form
Background Images
struct Form_RowBackgroundImage : View {
var body: some View {
Form {
Section {
Text("Images can be on a row or a section.")
Text("Image on one row.")
.listRowBackground(Image("water")
.blur(radius: 3))
} header: {
Text("Images on Rows")
}
Section {
Text("Row 1.")
Text("Row 2.")
Text("Row 3.")
} header: {
Text("Images")
} Notice when the image is
.listRowBackground(Image("water") on the section, it is
.blur(radius: 3)) repeated for all rows.
}
.font(.title2)
}
}
www.bigmountainstudio.com 142
Form
Text("Top")
.listRowInsets(EdgeInsets(top: -20, leading: 40, bottom: 0, trailing: 0))
Text("Bottom")
.listRowInsets(EdgeInsets(top: 20, leading: 40, bottom: 0, trailing: 0))
} header: {
Text("Form")
.font(.title)
.foregroundStyle(.gray)
}
}
.font(.title2)
}
}
www.bigmountainstudio.com 143
Form
With Controls
struct Form_WithControls : View {
@State private var isOn = true
@State private var textFieldData = "This is a text field"
www.bigmountainstudio.com 144
Form
Form {
DisclosureGroup("Audio Settings", isExpanded: $settingsExpanded) {
VStack {
Toggle("Treble", isOn: $trebleOn)
Toggle("Bass", isOn: $bassOn)
Slider(value: $levels)
}
.font(.title2) Normally the tint would also
.padding() change the DisclosureGroup s
} label. But in a Form, it does
}
not.
}
.font(.title)
.tint(.purple)
} See Control Views >
} DisclosureGroup for more info.
www.bigmountainstudio.com 145
’
Gauge
iOS 16
Gauge
www.bigmountainstudio.com 146
GroupBox
iOS 14
GroupBox
Box
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
The GroupBox is a pull-in view.
www.bigmountainstudio.com 147
iOS 14
Label
Label
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 148
LabeledContent
iOS 16
LabeledContent
ခ
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
This view pushes out horizontally.
www.bigmountainstudio.com 149
Link
iOS 14
Link
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 150
List
Using a List view is the most efficient way of displaying vertically scrolling data. You can display data in a ScrollView, as you
will see later on, but it will not be as efficient in terms of memory or performance as the List view.
www.bigmountainstudio.com 151
List
List {
Text("Line One")
Text("Line Two")
Text("Line Three")
Image("profile") 💡
Button("Click Here", action: {})
.foregroundColor(.green) Note: Like other container views,
HStack { you can now have as many views as
Spacer()
you want inside it.
Text("Centered Text")
Spacer()
}.padding()
}
.font(.title)
}
}
}
www.bigmountainstudio.com 152
List
With Data
struct List_WithData : View {
var stringArray = ["This is the simplest List", "Evans", "Lemuel James Guerrero", "Mark",
"Durtschi", "Chase", "Adam", "Rodrigo", "Notice the automatic wrapping when the text is longer"]
In this scenario, we are using “self” to say, “Just use the value of the string itself to uniquely identify
each row.”
www.bigmountainstudio.com 153
List
Custom Rows
struct List_CustomRows : View {
var data = ["Custom Rows!", "Evans", "Lemuel James Guerrero", "Mark", "Durtschi", "Chase",
"Adam", "Rodrigo"]
www.bigmountainstudio.com 154
List
Move Rows
struct List_MoveRow : View {
@State var data = ["Hit the Edit button to reorder", "Practice Coding", "Grocery shopping",
"Get tickets", "Clean house", "Do laundry", "Cook dinner", "Paint room"]
What is EditButton()?
This is a built-in function that returns a view (Button) that will automatically toggle edit mode on the List.
Its text says “Edit” and then when tapped you will see the move handles appear on the rows and the
button text says “Done”.
www.bigmountainstudio.com 155
List
Delete Rows
struct List_Delete : View {
@State var data = ["Swipe to Delete", "Practice Coding", "Grocery shopping", "Get tickets",
"Clean house", "Do laundry", "Cook dinner", "Paint room"]
These three functions only work on views that implement the DynamicViewContent protocol. Currently,
the only view that conforms to the DynamicViewContent protocol is the ForEach view. So these
functions are only available on a ForEach view, not a List view.
www.bigmountainstudio.com 156
List
Selecting a Row
struct List_Selection_Single: View {
@State private var data = ["Practice Coding", "Grocery shopping", "Get tickets",
Text(item)
}
Then bind the selection parameter
Text("To do first: ") +
to your @State property above using
Text(selection ?? "") the dollar sign ($).
.bold()
.font(.title)
.navigationTitle("List")
www.bigmountainstudio.com 157
List
@State private var data = ["Practice Coding", "Grocery shopping", "Get tickets",
NavigationStack {
Text(item)
.font(.title)
.navigationTitle("List")
.toolbar { EditButton() }
www.bigmountainstudio.com 158
List
SelectionDisabled iOS 17
@State private var data = ["Things to do", "Practice Coding", "Grocery shopping",
“Get tickets", "Clean house", "Do laundry", "Cook dinner", "Paint room"]
NavigationStack {
VStack(spacing: 0) {
Text(item)
Use width: 214 .selectionDisabled(item == "Things to do")
}
If you do not want a row to
.font(.title) be selected, you can use the
.navigationTitle("List") selectionDisabled modifier.
}
www.bigmountainstudio.com 159
List
www.bigmountainstudio.com 160
List
// This logic was inline but the compiler said it was "too complex" 🤷
private func getTextColor(due: String) -> Color {
due == "Today" ? Color.black : Color.primary
}
}
www.bigmountainstudio.com 161
List
www.bigmountainstudio.com 162
List
List {
ForEach(self.data) { datum in
Text(datum.action)
.font(.title)
.padding()
// Inset row based on data
I m using a condition here to
.listRowInsets(EdgeInsets(top: 0,
determine just how much to inset
leading: datum.isIndented ? 60 : 20,
the row.
bottom: 0, trailing: 0))
}
}
.listStyle(.plain)
}
}
}
💡 💡
Note: If you want to remove all default Note: If you want a row content to go to
edge insets (setting all to zero), you can not be indented at all (so it touches the
use: edge of the list, then set the leading
.listRowInsets(EdgeInsets()) edge to zero.
www.bigmountainstudio.com 163
’
List
www.bigmountainstudio.com 164
List
ListStyle: Automatic
struct List_ListStyle_Automatic: View {
var body: some View {
VStack(spacing: 20) {
HeaderView("List",
subtitle: "List Style: Automatic",
desc: "You can apply different styles to lists. Here is what a list looks
like using the default style 'automatic'.",
back: .green)
List {
Text("What would you like to learn?")
.font(.title2)
.fontWeight(.bold)
Label("Learn Geography", systemImage: "signpost.right.fill")
Label("Learn Music", systemImage: "doc.richtext")
Label("Learn Photography", systemImage: "camera.aperture")
Label("Learn Art", systemImage: "paintpalette.fill")
.font(Font.system(.title3).weight(.bold))
Label("Learn Physics", systemImage: "atom")
Label("Learn 3D", systemImage: "cube.transparent")
Label("Learn Hair Styling", systemImage: "comb.fill")
}
.accentColor(.green)
.listStyle(.automatic)
💡
}
.font(.title) Note: You do not have to apply
} this modifier if the value is
} automatic. This is the default.
www.bigmountainstudio.com 165
Link
iOS 14 iOS 15 iOS 16
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 166
iOS 14
Menu
The Menu view allows you to attach actions to a view. You basically add some buttons (with or without images) and define a
label, or a visible view to the user. When the user taps the label, the actions will show.
This SwiftUI chapter is locked in this
This is similar to the contextMenu modifier (in the Controls Modifiers chapter) where you can attach a menu to any view
preview.
that becomes visible when you long-press the view.
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 167
MultiDatePicker
iOS 16
MultiDatePicker
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 168
NavigationStack
iOS 16
NavigationStack
The NavigationStack is slightly different in that it will fill the whole screen when used. You will never have to specify its size. It is used to
help you navigate from one screen to another with built-in ways to navigate forward and back. This chapter will also teach you how to use
and customize the navigation stack.
www.bigmountainstudio.com 169
NavigationStack
Introduction
struct Navigation_Intro : View {
By default, the navigation stack will
var body: some View {
not show anything if there is no title
NavigationStack { modifier added for it to use.
Image(systemName: "hand.wave.fill")
.font(.largeTitle) The navigation stack bar is there at
} the top, you just can t see it.
}
}
www.bigmountainstudio.com 170
’
NavigationStack
Navigation Title
struct Navigation_NavigationTitle: View { The navigation stack will look
var body: some View { for a navigation title modifier
NavigationStack { INSIDE itself.
Text("😃 ")
.navigationTitle("Navigation Stack Title") By default, a larger navigation
} bar is used for the navigation
.font(.title) stack.
}
}
⚠
Warning: If you put the navigation
title on the navigation stack itself, it
will not work.
www.bigmountainstudio.com 171
NavigationStack
Background Color
struct Navigation_BackgroundColor: View { The contents of the navigation stack
var body: some View { is within the safe area.
NavigationStack {
ZStack {
Where the nav bar is on top is an
“unsafe area”.
Color.green.opacity(0.25)
.ignoresSafeArea()
If you want a color to go behind the
navigation stack s title bar, then you
Color.gray.opacity(0.25) will have to ignore that safe area
} edge (or all edges).
.navigationTitle("Background Color")
}
} This gray color gives you a better
} idea where the safe area is and
where the edge is against the
navigation stack s title bar.
www.bigmountainstudio.com 172
’
’
NavigationStack
www.bigmountainstudio.com 173
’
’
NavigationStack
UINavigationBarAppearance iOS 15
}
.navigationTitle("Appearance")
.font(.title)
}
.onAppear {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = UIColor(Color.green.opacity(0.25))
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
}
}
💡
Note: You could also set this when the app starts on the very first view of your app.
www.bigmountainstudio.com 174
NavigationStack
Display Mode
struct Navigation_DisplayMode: View {
var body: some View {
NavigationStack {
VStack {
Divider()
Spacer()
}
.navigationTitle("Inline Display Mode")
.navigationBarTitleDisplayMode(.inline)
}
}
}
💡
Note: If you navigate from
this screen, the next one will
also have an inline bar title.
www.bigmountainstudio.com 175
NavigationStack
NavigationBarHidden
struct Navigation_BarHidden: View {
@State private var isHidden = false
www.bigmountainstudio.com 176
NavigationStack
www.bigmountainstudio.com 177
NavigationStack
NavigationBarBackButtonHidden
www.bigmountainstudio.com 178
NavigationStack
(Code) NavigationBarBackButtonHidden
// First Screen
struct Navigation_BackButtonHidden: View {
var body: some View {
Use NavigationLink to navigate
NavigationStack {
to a new screen.
NavigationLink("Go To Detail", destination: BackButtonHiddenDetail())
More about NavigationLink in
.font(.title)
the next section.
.navigationTitle("Navigation Views")
}
}
}
// Second Screen
struct BackButtonHiddenDetail: View {
This will allow you to
@Environment(\.dismiss) var dismiss
navigate backward.
var body: some View {
Button("Go Back") {
dismiss() Dismissing what is being presented will
} navigate you back to the previous screen.
.font(.title)
.navigationTitle("Detail View")
// Hide the back button
The back button is hidden. This allows you to create a
.navigationBarBackButtonHidden(true)
custom back button where you might want to add logic to it.
}
}
www.bigmountainstudio.com 179
NavigationStack
⚠
Warning: By hiding the back button, you will lose the
}
ability to swipe back to the previous screen.
www.bigmountainstudio.com 180
’
NavigationStack
www.bigmountainstudio.com 181
NavigationSplitView
iOS 16
NavigationSplitView
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 182
NavigationLink
NavigationLink
The NavigationLink is your way to navigate to another view. It ONLY works inside of a NavigationView. The appearance is
just like a Button. You can customize it just like you can customize a Button too.
www.bigmountainstudio.com 183
NavigationLink
Introduction
struct NavLink_Intro: View { Use NavigationLink to navigate to a
var body: some View { new view inside a NavigationStack.
NavigationStack {
VStack(spacing: 20) {
NavigationLink("Just Text", destination: SecondView())
NavigationLink {
SecondView()
} label: {
Label("Label", systemImage: "doc.text.fill")
}
}
.navigationTitle("NavigationLink")
}
.font(.title)
} You can also use the label
} parameter to customize the
tappable view to trigger
struct SecondView: View { navigation.
var body: some View {
VStack {
Text("View 2")
These are the basic
.font(.largeTitle)
implementations using just text or
}
a label and a destination. The
.navigationTitle("Second View")
destination can be any view.
}
}
www.bigmountainstudio.com 184
NavigationLink
Customization
struct NavLink_Customization: View { You can customize NavigationLink
var body: some View { just like you would with a Button.
NavigationStack {
VStack(spacing: 20) {
NavigationLink(destination: SecondView()) {
Text("Navigate")
.foregroundStyle(.white)
.padding()
}
.buttonStyle(.borderedProminent)
.tint(.pink)
www.bigmountainstudio.com 185
NavigationLink
www.bigmountainstudio.com 186
NavigationLink
www.bigmountainstudio.com 187
NavigationLink
isPresented iOS 16
}
}
⚠
.font(.title)
}
Warning: The navigationDestination has to
} be outside the sheet for this to work.
www.bigmountainstudio.com 188
NavigationLink
enum Screens {
You can also use an enum to keep
case screen1
case screen2
track of all of your screens.
case screen3
}
www.bigmountainstudio.com 189
’
NavigationLink
NavigationController
class NavigationController {
This navigate function returns the view to navigate to.
@ViewBuilder
static func navigate(to screen: Screens) -> some View {
switch screen {
case .screen1:
Image(systemName: "1.square.fill").font(.largeTitle).foregroundStyle(.green)
case .screen2:
Image(systemName: "2.square.fill").font(.largeTitle).foregroundStyle(.red)
case .screen3:
Image(systemName: "3.square.fill").font(.largeTitle).foregroundStyle(.purple)
}
}
}
💡
This is a good method when you:
1. Have no data to pass into your views.
2. Pass in the same object/data to all of your screens.
3. Keep data in a global location where all your views can access it.
www.bigmountainstudio.com 190
NavigationLink
NavigationPath iOS 16
www.bigmountainstudio.com 191
NavigationLink
.navigationTitle("Pop to Root")
The key is to make sure
.navigationDestination(for: String.self) { pathValue in your navigation path array
if pathValue == "View 2" { (navPath in this example) is
NavLinkView2(navPath: $navPath) accessible to all destination
views.
} else {
NavLinkView3(navPath: $navPath)
In this example, it is being
} passed into the destination
} views.
}
See next page for how the
.font(.title)
destination views pop back
} to the root (first) view.
}
www.bigmountainstudio.com 192
NavigationLink
NavigationLink("Navigate Here") {
By default, a navigation link
NavigationDestinationView()
will navigate to the detail
}
column. .isDetailLink(false) // Do not navigate to detail column
}
.navigationTitle("NavigationLink")
} detail: { Use isDetailLink modifier to
Text("Detail") control where navigation
}
happens.
.font(.title)
}
} If it is true (default) the
destination will appear in the
struct NavigationDestinationView: View { detail column.
var body: some View {
VStack(spacing: 20) { If false, the destination will
Text("Navigation Destination")
appear in the SAME column.
}
.navigationTitle("Destination")
.font(.title)
}
}
www.bigmountainstudio.com 194
iOS 14
OutlineGroup
OutlineGroups gives you another way to present hierarchical data. It is very similar to using a List with the children parameter. Except this
container view does not scroll. It s probably best for limited data.
www.bigmountainstudio.com 195
’
OutlineGroup
Introduction iOS 14
www.bigmountainstudio.com 196
OutlineGroup
iOS 14
www.bigmountainstudio.com 197
iOS 14
OutlineGroup
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 198
’
Picker
To get or set a value for the Picker, you need to bind it to a variable. This variable is then passed into the Picker s initializer.
Then, all you need to do is change this bound variable s value to select the row you want to show in the Picker. Or read the
bound variable s value to see which row is currently selected. One thing to note is that this variable is actually bound to the
Picker row s tag property which you will see in the following pages.
www.bigmountainstudio.com 199
’
’
’
’
Picker
Introduction
struct Picker_Intro : View {
Starting in iOS 15, the default picker
@State private var favoriteState = 1
style will look like the menu style.
(Before, the default was the wheel
var body: some View {
style.)
VStack(spacing: 20) { iOS 15
HeaderView("Picker",
subtitle: "Introduction",
desc: "You can associate a property with the picker rows' tag values.")
Spacer()
}
.font(.title)
💡
}
}
www.bigmountainstudio.com 200
’
Picker
Sections
struct Picker_Sections: View {
@State private var favoriteState = 1
Section {
Text("Vermont").tag(2)
Text("New Hampshire").tag(3)
} header: {
Text("East")
}
}
Spacer()
}
.font(.title)
}
}
www.bigmountainstudio.com 201
Picker
Wheel Style
struct Picker_Wheel: View {
This will be the default value
@State private var yourName = "Mark"
selected in the Picker.
var body: some View {
VStack(spacing: 20) {
HeaderView("Picker",
subtitle: "Wheel Style",
desc: "You can change the way a Picker looks by using the pickerStyle
modifier.")
www.bigmountainstudio.com 202
Picker
Programmatic Selection
struct Picker_ProgrammaticSelection: View {
@State private var favoriteState = 1
www.bigmountainstudio.com 203
’
Picker
Customized
struct Picker_Customized : View {
@State private var favoriteState = 1
@State private var youTuberName = "Mark"
www.bigmountainstudio.com 204
Picker
www.bigmountainstudio.com 205
Picker
Text("Selected: \(youTuberName)")
}
.font(.title)
}
}
www.bigmountainstudio.com 206
Picker
Pickers in Forms
struct Picker_InForm: View {
@State private var selectedDaysOption = "2" Picker styles can alter the appearance
var numberOfDaysOptions = ["1", "2", "3", "4", "5"] of a picker when inside a form. Here
are some of the different options.
var body: some View {
VStack {
Form {
Picker("Frequency", selection: $selectedDaysOption) {
ForEach(numberOfDaysOptions, id: \.self) {
Text("\($0) Days").tag($0)
}
}
Picker("Frequency", selection: $selectedDaysOption) {
ForEach(numberOfDaysOptions, id: \.self) {
Text("\($0) Days").tag($0)
}
}
.pickerStyle(.menu) // Add this modifier to make it use the accent color
Picker("Frequency", selection: $selectedDaysOption) {
ForEach(numberOfDaysOptions, id: \.self) {
Text("\($0) Days").tag($0)
} Notice the inline style
} created its own section
.pickerStyle(.inline)
within the form.
Picker("Frequency", selection: $selectedDaysOption) {
ForEach(numberOfDaysOptions, id: \.self) {
Text("\($0) Days").tag($0)
}
}
.pickerStyle(.wheel)
}
.navigationTitle("Picker")
}
.font(.title)
}
}
www.bigmountainstudio.com 207
PhotosPicker
iOS 16
PhotosPicker
SAVE
The photos picker view (the button 10%
part) AND
is a UNLOCK
pull-in view. THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 208
iOS 14
ProgressView
209
RenameButton
iOS 16
RenameButton
www.bigmountainstudio.com 210
’
ScrollView
A ScrollView is like a container for child views. When the child views within the ScrollView go outside the frame, the user
can scroll to bring the child views that are outside the frame into view.
A ScrollView is a push-out view in the scroll direction you specify. You can set the direction of a ScrollView to be vertical or
horizontal.
www.bigmountainstudio.com 211
ScrollView
Introduction
struct Scrollview_Intro : View {
@State private var names = ["Scott", "Mark", "Chris", "Sean", "Rod", "Meng", "Natasha",
"Chase", "Evans", "Paul", "Durtschi", "Max"]
var body: some View { Wrap the ForEach in a ScrollView.
ScrollView {
ForEach(names, id: \.self) { name in
HStack {
Text(name).foregroundStyle(.primary)
Image(systemName: "checkmark.seal.fill")
.foregroundStyle(.green)
Spacer()
}
.padding()
.background(Color.white.shadow(.drop(radius: 1, y: 1)),
in: RoundedRectangle(cornerRadius: 8))
.padding(.bottom, 4)
}
.padding(.horizontal)
}
.font(.title)
}
}
A Scrollview with a ForEach view is similar to a List. But be warned, the rows are not reusable. It is best
to limit the number of rows for memory and performance considerations.
www.bigmountainstudio.com 212
ScrollView
SafeAreaInset iOS 15
www.bigmountainstudio.com 213
ScrollView
Scroll Horizontally
struct Scrollview_Horizontal : View {
For horizontal scrolling,
var items = [Color.green, Color.blue, Color.purple, Color.pink, set the scroll direction to
Color.yellow, Color.orange] horizontal with an HStack.
If the contents extend
var body: some View { horizontally beyond the
GeometryReader { gr in
screen s frame, then
scrolling will be enabled.
ScrollView(Axis.Set.horizontal, showsIndicators: true) {
HStack {
RoundedRectangle(cornerRadius: 15)
.fill(item)
www.bigmountainstudio.com 214
’
’
ScrollView
www.bigmountainstudio.com 216
Searchable
iOS 15
Searchable
www.bigmountainstudio.com 217
SecureField
In order to get or set the text in a SecureField, you need to bind it to a variable. This variable is passed into the
SecureField s initializer. Then, all you need to do is change this bound variable s text to change what is in the SecureField.
Or read the bound variable s value to see what text is currently in the SecureField.
www.bigmountainstudio.com 218
’
’
’
SecureField
Introduction
@State private var userName = ""
@State private var password = ""
...
VStack(spacing: 20) {
Image("Logo")
Spacer()
Text("SecureField")
.font(.largeTitle)
Text("Introduction")
.font(.title)
.foregroundColor(.gray)
www.bigmountainstudio.com 219
SecureField
Customizations
@State private var userName = ""
@State private var password = ""
...
ZStack{
RoundedRectangle(cornerRadius: 8)
.foregroundColor(.purple)
TextField("user name", text: $userName)
.foregroundColor(Color.white)
.padding(.horizontal)
}
.frame(height: 40)
.padding(.horizontal)
RoundedRectangle(cornerRadius: 8)
.foregroundColor(.purple)
.overlay(
SecureField("password", text: $password)
.foregroundColor(Color.white)
.padding(.horizontal)
)
.frame(height: 40)
.padding(.horizontal)
www.bigmountainstudio.com 220
SecureField
Customization Layers
@State private var userName = ""
@State private var password = ""
...
VStack(spacing: 20) {
Text("SecureField")
.font(.largeTitle)
Text("Customization Layers")
.font(.title)
.foregroundColor(.gray)
Text("You can also add a background to the SecureField. It's all the same idea: adjust the
layers.")
...
Image("SecureFieldLayers")
Text("The highlighted layer in that image is the actual text field layer of the view.")
.font(.title)
.padding(.horizontal)
}
www.bigmountainstudio.com 221
SecureField
HeaderView("SecureField",
subtitle: "Keyboard Safe Area",
desc: "SecureFields will automatically move into view when the keyboard
appears. The keyboard adjusts the bottom safe area so it will not cover views.",
back: .purple, textColor: .white)
www.bigmountainstudio.com 222
Segmented Control (Picker)
Segmented controls are now Picker controls with a different picker style set. In order to get or set the selected segment,
you need to bind it to a variable. This variable is passed into the segmented control s (Picker s) initializer. Then, all you need
to do is change this bound variable s value to change the selected segment. Or read the bound variable s value to see
which segment is currently selected.
www.bigmountainstudio.com 223
’
’
’
’
Segmented Control (Picker)
Introduction
@State private var dayNight = "day"
@State private var tab = 1
...
VStack(spacing: 20) {
Text("Segmented Control (Picker)").font(.largeTitle)
Text("Introduction")
.font(.title).foregroundColor(.gray)
Text("Associate the segmented control with an @State variable that will control which
segment is selected. The state variable will match each segment's tag value.")
...
Text("With Images:")
www.bigmountainstudio.com 224
Segmented Control (Picker)
No Segment Selected
@State private var selection = 0
...
VStack(spacing: 20) {
Text("Segmented Control (Picker)").font(.largeTitle)
Text("No Segment Selected")
.font(.title).foregroundColor(.gray)
Text("This segmented control will have nothing selected because the default state variable
does not match any of the segment tag values.")
...
www.bigmountainstudio.com 225
Segmented Control (Picker)
Colors
struct SegmentedControl_Colors: View {
@State private var selection = 2 You can change the color of segmented
controls by using the background modifier.
var body: some View {
VStack(spacing: 60) {
Picker("", selection: $selection) {
Text("One").tag(1)
Text("Two").tag(2)
Text("Three").tag(3)
}
.pickerStyle(.segmented)
.background(Color.pink)
www.bigmountainstudio.com 226
ShareLink
iOS 16
ShareLink
This is a pull-in view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 227
iOS 14
SignInWithAppleButton
ဈ
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 228
Slider
When using a Slider view, the default range of values is 0.0 to 1.0. You bind the Slider to a state variable, usually a number
type, like an Int. But it doesn t have to be a number type. It can be any type that conforms to the Stridable protocol.
(“Stride” means to “take steps in a direction; usually long steps”.) A type that conforms to Stridable (such as an Int) means it
has values that are continuous and can be stepped through and measured. (“Step through”, “Stride”, I think you see the
connection now.)
You use the bound variable to set or get the value the Slider s thumb (circle) is currently at.
www.bigmountainstudio.com 229
’
’
Slider
Introduction
struct Slider_Intro : View {
@State private var sliderValue = 0.5 Value used for the slider.
}.font(.title)
}
}
www.bigmountainstudio.com 230
’
Slider
www.bigmountainstudio.com 231
Slider
Customization
@State private var sliderValue = 0.5
...
Text("At the time of this writing, there isn't a way to color the thumb. But we can change the
background color and apply some other modifiers.")
…
Slider(value: $sliderValue)
.padding(.horizontal, 10)
.background(Color.orange)
.shadow(color: .gray, radius: 2)
.padding(.horizontal)
Slider(value: $sliderValue)
.padding(.horizontal)
.accentColor(.orange)
Slider(value: $sliderValue)
.padding(10)
.background(Capsule().stroke(Color.orange, lineWidth: 2))
.padding(.horizontal)
Slider(value: $sliderValue)
.padding(10)
.background(Capsule().fill(Color.orange))
.accentColor(.black)
.padding(.horizontal)
www.bigmountainstudio.com 232
Slider
With Images
struct Slider_WithImages : View {
@State private var sliderValue = 0.5
Slider(value: $sliderValue,
minimumValueLabel: Image(systemName: "tortoise"),
maximumValueLabel: Image(systemName: "hare"), label: {})
.foregroundColor(.green)
.padding()
Slider(value: $sliderValue,
minimumValueLabel: Text("0"), Use minimum and
maximumValueLabel: Text("1"), label: {}) maximum value labels
.padding()
to add text or images
VStack { to the ends of the
Slider(value: $sliderValue) slider.
.accentColor(.orange)
HStack {
Image(systemName: "circle")
Spacer()
Image(systemName: "circle.righthalf.fill")
Spacer()
Image(systemName: "circle.fill")
}
.foregroundColor(.orange)
.padding(.top, 8)
}.padding()
}.font(.title)
}
}
www.bigmountainstudio.com 233
Slider
Tint iOS 15
VStack(spacing: 20) {
HeaderView("Slider",
subtitle: "Tint",
desc: "Tint can also be used to change the color of the Slider's track.")
Slider(value: $sliderValue,
.foregroundColor(.green)
.tint(.orange)
.padding()
.font(.title)
www.bigmountainstudio.com 234
Stepper
When using a Stepper view, you bind it to a state variable, usually a number. But it doesn t have to be a number type. It can
be any type that conforms to the Stridable protocol. (“Stride” means to “take steps in a direction; usually long steps”.) A
type that conforms to Stridable means it has values that are continuous and can be stepped through and measured. (“Step
through”, “Stride”, I think you see the connection now.)
You use the bound variable to set or get the value it is currently at.
This is a horizontal push-out view. Vertically it is pull-in.
www.bigmountainstudio.com 235
’
Stepper
Introduction
@State private var stepperValue = 1
@State private var values = [0, 1]
...
VStack(spacing: 20) {
Text("Stepper")
.font(.largeTitle)
Text("Introduction")
.font(.title).foregroundColor(.gray)
Text("The Stepper can be bound to a variable like this:")
...
Stepper(value: $stepperValue) {
Text("Bound Stepper: \(stepperValue)")
}.padding(.horizontal)
Divider()
Image(systemName: "bolt.fill")
.font(.title).foregroundColor(.yellow)
Text("Or you can run code on the increment and decrement events:")
.frame(maxWidth: .infinity).padding()
.background(Color.blue).foregroundColor(Color.white)
.font(.title)
Stepper(onIncrement: {self.values.append(self.values.count)},
onDecrement: {self.values.removeLast()}) {
Text("onIncrement and onDecrement")
}.padding(.horizontal)
HStack {
ForEach(values, id: \.self) { value in
Image(systemName: "\(value).circle.fill")
}
}.font(.title).foregroundColor(.green)
}
www.bigmountainstudio.com 236
Stepper
Label Options
struct Stepper_LabelsHidden: View {
@State private var stepperValue = 1
💡
Note: Even though the label/title is not shown, I would still recommend having one because it will still
be used for accessibility purposes.
www.bigmountainstudio.com 237
Stepper
Range
@State private var stars = 0
VStack(spacing: 20) {
Text("Stepper")
.font(.largeTitle)
.padding()
Text("Range of Values")
.font(.title)
.foregroundColor(.gray)
Text("You can set a range for the stepper too. In this example, the range is between one and
five.")
...
HStack {
ForEach(1...stars, id: \.self) { star in
Image(systemName: "star.fill")
}
}
.font(.title)
.foregroundColor(.yellow)
}
When the Stepper reaches the range limits, the corresponding plus or minus button will appear as disabled. In
this screenshot, notice the plus button is disabled.
www.bigmountainstudio.com 238
Stepper
Customization
@State private var contrast = 50
...
Text("A foreground and background color can be set.")
...
Text("Notice the minus and plus buttons are not affected. The platforms determine how this will
be shown.")
...
www.bigmountainstudio.com 239
Stepper
Colors
Text("There is no built-in way to change the color of the stepper that I have found. Instead, I
had to hide the label and apply a color behind it.”)
...
HStack {
Text("My Custom Colored Stepper")
Spacer()
Stepper("", value: $contrast)
.background(Color.teal, in: RoundedRectangle(cornerRadius: 9))
.labelsHidden() // Hide the label
}
HStack {
Text("My Custom Colored Stepper")
Spacer()
Stepper("", value: $contrast)
.background(Color.orange, in: RoundedRectangle(cornerRadius: 9))
.cornerRadius(9)
.labelsHidden() // Hide the label
}
www.bigmountainstudio.com 240
TabView
The TabView acts like a container for child views within it. These child views are individual screens. It provides tab buttons
(TabItems) that allows the user to switch between these child views.
www.bigmountainstudio.com 241
TabView
Introduction
struct TabView_Intro : View {
var body: some View {
TabView {
// First Screen
VStack(spacing: 20) {
HeaderView("TabView",
subtitle: "Introduction",
desc: "The TabView view can hold multiple views, one for each tab.")
Text("At the end of a view, you add .tabItem modifier to show a button that
allows navigation to that view.")
.padding()
Image("TabItem")
}
.tabItem {
// Creates a tab button in the tab bar
Text("Tab 1")
}
// Second Screen
Text("This view represents the Second Screen.")
.tabItem {
// Creates a tab button in the tab bar
Text("Tab 2")
}
}
.font(.title)
}
}
www.bigmountainstudio.com 242
TabView
TabItems
struct TabView_TabItems : View {
var body: some View {
TabView {
TabOne()
.tabItem {
Text("Tab Text") Can be just text.
}
Text("Phone Calls")
.tabItem {
Image(systemName: "phone") Or just an image.
}
Text("Outgoing Phone Calls")
.tabItem {
Image(systemName: "phone.arrow.up.right") Can use both.
Text("Outgoing")
Order doesn t matter.
}
Text("Messages")
.tabItem {
Label("Messages", systemImage: "phone.and.waveform.fill")
}
}
} iOS 14
}
You can even use a Label
struct TabOne: View { for the text and image.
var body: some View {
VStack(spacing: 20) {
HeaderView("TabView",
subtitle: "Tab Items",
desc: "TabItems can accept Text, Image or both. Notice the order of Text
and Image does not matter for the tabItem.")
.font(.title)
}
}
}
www.bigmountainstudio.com 243
’
TabView
When there are too many tabs to fit for the device, the More button is created where you can find
the rest of the tabs listed out.
www.bigmountainstudio.com 244
TabView
Navigation
struct TabView_Navigating : View {
@State private var selectedTab = 1 // Set which tab is active
Button("Go to Tab 2") { Change the state property bound to the TabView s
selectedTab = 2 selection parameter to navigate to a different tab.
}
.tabItem {
Image(systemName: "star.fill")
} Add tags to enable programmatically
.tag(1)
navigating to tabs.
// Tab 2
VStack {
Text("Second Screen")
}
.tabItem {
Image(systemName: "moon.fill")
}
.tag(2)
}
.font(.title)
}
}
www.bigmountainstudio.com 245
’
TabView
Colors
struct TabView_Colors : View {
var body: some View {
TabView {
// Tab 1
VStack(spacing: 20) {
HeaderView("TabView",
subtitle: "Tab Item Colors",
desc: "Set the color of the active tab item by setting the tint
color for the TabView.")
Image("AccentColor")
}
.tabItem {
Image(systemName: "star.fill")
}
// Tab 2
Text("Second Screen")
.tabItem {
Image(systemName: "moon.fill") Notice that I am setting the foreground style
} of the second tabItem to red. This will have
.foregroundStyle(Color.red) no effect on the color of the tab item. The
// Tab 3 background modifier will not work either.
Text("Third Screen")
.tabItem {
Image(systemName: "sun.min.fill")
}
}
.font(.title)
.tint(.yellow) Use tint to change the color of the active tab.
}
}
www.bigmountainstudio.com 246
TabView
Text("Original SF Symbols:")
Image(systemName: "star")
Image(systemName: "moon")
Image(systemName: "sun.min")
www.bigmountainstudio.com 247
TabView
Badge iOS 15
}
.tabItem {
Image(systemName: "house")
Text("Home")
}
// Tab 2
VStack {
Text("Messages")
}
.tabItem {
Image(systemName: "envelope") 💡
Text("Messages")
} Note: The operating system will set
.badge(15) the color of the badge.
} There isn t a way to change the color.
.font(.title)
}
}
www.bigmountainstudio.com 248
’
TabView
Background iOS 15
VStack {
Text("Messages")
Spacer()
Divider() Using this modifier allows you to
.background(Color.brown.opacity(0.5)) provide different backgrounds
} per tab view if you wanted.
.tabItem {
Image(systemName: "envelope")
Text("Messages")
}
}
.font(.title)
}
}
www.bigmountainstudio.com 249
TabView
www.bigmountainstudio.com 250
TabView
UITabBarAppearance iOS 15
www.bigmountainstudio.com 251
iOS 14
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 252
Text
The text view will probably be one of your most-used views. It has many, if not the most, modifiers available to it.
www.bigmountainstudio.com 253
Text
Line Limit
VStack(spacing: 20) {
Text("Text")
.font(.largeTitle)
Text(“Line Limit”)
.font(.title)
.foregroundColor(.gray)
Image("LineLimit")
Text("The Text view shows read-only text that can be modified in many ways. It wraps
automatically. If you want to limit the text wrapping, add .lineLimit(<number of lines here>).")
...
www.bigmountainstudio.com 254
Text
Text Styles
struct Text_TextStyles: View {
var body: some View {
VStack(spacing: 10) {
Image("Font")
HeaderView("Text",
subtitle: "Text Styles",
desc: "You can add a TextStyle to the Text view by using the .font
modifier.",
back: .green, textColor: .white)
.font(.title)
Group {
Text("Font.largeTitle").font(.largeTitle)
Text("Font.title").font(.title)
Text("Font.title2 (iOS 14)").font(.title2)
iOS 14
Text("Font.title3 (iOS 14)").font(.title3)
}
Group {
Text("Font.headline").font(.headline)
Text("Font.body").font(.body)
Text("Font.callout").font(.callout)
Text("Font.subheadline").font(.subheadline)
Text("Font.footnote").font(.footnote)
Text("Font.caption").font(.caption)
Text("Font.caption2 (iOS 14)").font(.caption2) iOS 14
}
}
}
}
www.bigmountainstudio.com 255
Text
Weights
Text("Text")
.font(.largeTitle)
Text("Font Weights")
.font(.title)
.foregroundColor(.gray)
Image("FontWeight")
Text("You can apply a variety of font weights to the Text view.")
.padding()
.frame(maxWidth: .infinity)
.background(Color.green)
.foregroundColor(.white)
.font(.title)
💡
.fontWeight(.ultraLight)
Text("Thin")
.fontWeight(.thin)
Text("Light")
.fontWeight(.light) Note: The fontWeight modifier can ONLY be
Text("Regular") applied to Text views.
.fontWeight(.regular)
Text("Medium")
.fontWeight(.medium) Unlike the font modifier which can be applied
Text("Semibold") to any view.
.fontWeight(.semibold)
Text("Bold")
To apply weight to any view using the font
.fontWeight(.bold)
Text("Heavy") modifier, see next page.
.fontWeight(.heavy)
Text("Black")
.fontWeight(.black)
}.font(.title)
www.bigmountainstudio.com 256
Text
Text("Ultralight - Title")
.fontWeight(.ultraLight)
.font(.title)
Text("Thin - Body") 💡
.fontWeight(.thin)
.font(.body) Note: Instead of two modifiers, you
Text("Light - Large Title") can combine text style and weight in
.fontWeight(.light) just ONE modifier like this.
.font(.largeTitle)
Text("Bold - Callout")
.fontWeight(.bold)
.font(.callout)
Text("Black - Title")
.font(Font.title.weight(.black))
}
}
}
www.bigmountainstudio.com 257
Text
Font Design
struct Text_FontDesign : View {
var body: some View {
VStack(spacing: 10) {
HeaderView("Text", subtitle: "Font Design", desc: "There are 4 font designs now in
iOS. Use Font.system to set the font design you want.",
back: .green, textColor: .white)
DescView(desc: "A \"serif\" is a little piece that comes off the letter.",
back: .green, textColor: .white)
Image("Serif")
}
.font(.title)
}
}
www.bigmountainstudio.com 258
Text
Formatting
@State private var modifierActive = true
...
HStack {
Image("Bold")
Text("Bold").bold()
}
HStack {
Image("Italic")
Text("Italic").italic()
}
HStack {
Image("Strikethrough")
Text("Strikethrough").strikethrough()
}
HStack {
Image("Strikethrough")
Text("Green Strikethrough")
.strikethrough(modifierActive, color: .green)
}
HStack {
Image("ForegroundColor")
Text("Text Color (ForegroundColor)").foregroundColor(.green)
}
HStack {
Image("Underline")
Text("Underline").underline()
}
HStack {
Image("Underline")
Text("Green Underline").underline(modifierActive, color: .green)
}
...
Toggle("Modifiers Active", isOn: $modifierActive)
www.bigmountainstudio.com 259
Text
Allows Tightening
VStack(spacing: 20) {
...
Image("AllowsTightening")
Text("You might want to tighten up some text that might be too long.")
...
Group {
Text("Allows tightening to allow text to fit in one line.")
.foregroundColor(.red)
.allowsTightening(false)
.padding(.horizontal)
.lineLimit(1)
Text("Allows tightening to allow text to fit in one line.")
.foregroundColor(.green)
.allowsTightening(true)
.padding(.horizontal)
.lineLimit(1)
}.padding(.horizontal)
}
Allows Tightening can be helpful when you see the last word getting truncated. Applying it may not even
fully work depending on just how much space can be tightened. With the default font, I notice I can get
a couple of characters worth of space to tighten up.
www.bigmountainstudio.com 260
Text
Group {
Text("This text is set to a minimum scale factor of 0.6.")
.lineLimit(1)
.minimumScaleFactor(0.6)
Text("This text is set to a minimum scale factor of 0.7.")
.lineLimit(1)
.minimumScaleFactor(0.7)
Text("This text is set to a minimum scale factor of 0.8.")
.lineLimit(1)
.minimumScaleFactor(0.8)
Text("This text is set to a minimum scale factor of 0.9.")
.lineLimit(1)
.minimumScaleFactor(0.9)
}
.truncationMode(.middle)
.padding(.horizontal)
}
.font(.title)
}
}
.minimumScaleFactor takes a fraction from 0 to 1. For example, 0.3 is 30% of the original size of the font
that it can shrink. If the font size is 100, then it can shrink to 30.
www.bigmountainstudio.com 261
Text
Line Spacing
VStack(spacing: 10) {
Text("Text").font(.largeTitle)
Text("Line Spacing").font(.title).foregroundColor(.gray)
Image("LineSpacing")
Text("You can use line spacing to add more space between lines of text. This text has no
line spacing applied:")
.font(.title)
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
.foregroundColor(Color.white)
Text("SwiftUI offers a Line Spacing modifier for situations where you want to increase the
space between the lines of text on the screen.")
.font(.title)
Text("SwiftUI offers a Line Spacing modifier for situations where you want to increase the
space between the lines of text on the screen.")
.lineSpacing(16.0) // Add spacing between lines
.font(.title)
}
www.bigmountainstudio.com 262
Text
Alignment
VStack(spacing: 20) {
Text("Text").font(.largeTitle)
Text("Multiline Text Alignment").foregroundColor(.gray)
Image("MultilineTextAlignment")
Text("By default, text will be centered within the screen. But when it wraps to multiple
lines, it will be leading aligned by default. Use multilineTextAlignment modifier to change
this!")
...
Text(".multilineTextAlignment(.center)")
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(Color.green)
Text(".multilineTextAlignment(.trailing)")
.frame(maxWidth: .infinity)
.padding()
.foregroundColor(.white)
.background(Color.green)
.allowsTightening(true) // Prevent truncation
Text("You are SUPER awesome for improving your skills by using this book!")
.multilineTextAlignment(.trailing) // Trailing align
.padding(.horizontal)
}
.font(.title) // Apply this text style to all text views
www.bigmountainstudio.com 263
Text
Truncation Mode
VStack(spacing: 20) {
Text("Text").font(.largeTitle)
Text("Truncation Mode").font(.title).foregroundColor(.gray)
Image("TruncationMode")
Text("When text gets truncated, you can control where the ellipsis (...) shows.")
.frame(maxWidth: .infinity).padding()
.foregroundColor(.white).background(Color.green)
.font(.title)
Text("Default: .truncationMode(.tail)")
.frame(maxWidth: .infinity).padding()
.foregroundColor(.white).background(Color.green)
.font(.title)
// Text automatically defaults at end
Text("This will be the best day of your life!")
.padding(.horizontal)
.lineLimit(1)
Text(".truncationMode(.middle)")
.frame(maxWidth: .infinity).padding()
.foregroundColor(.white).background(Color.green)
Text("This will be the best day of your life!")
.truncationMode(.middle) // Truncate in middle
.padding(.horizontal)
.lineLimit(1)
Text(".truncationMode(.head)")
.frame(maxWidth: .infinity).padding()
.foregroundColor(.white).background(Color.green)
Text("This will be the best day of your life!")
.truncationMode(.head) // Truncate at beginning
.padding(.horizontal)
.lineLimit(1)
}
.font(.title)
www.bigmountainstudio.com 264
Text
Group {
Text("You can also ").font(.title).fontWeight(.light)
+ Text("combine")
+ Text(" different font weights ").fontWeight(.black)
+ Text("and different text styles!").font(.title).fontWeight(.ultraLight)
}
.padding(.horizontal)
Although you see I m wrapping my Text views in a Group, it is not required. I only do this so I can apply common
modifiers to everything within the Group. See section on the Group view for more information.
www.bigmountainstudio.com 265
’
Text
Baseline Offset
struct Text_BaselineOffset : View {
var body: some View {
VStack(spacing: 20) {
Image("BaselineOffset")
HeaderView("Text",
subtitle: "Baseline Offset",
desc: "By default, your combined text will be on the same baseline, like
this:", back: .green, textColor: .white)
.font(.title)
.layoutPriority(1)
Text("100")
+ Text(" SWIFTUI ").font(.largeTitle).fontWeight(.light)
.foregroundColor(.blue)
+ Text ("VIEWS")
DescView(desc: "But you can offset each text view to create a cooler effect, like
this:", back: .green, textColor: .white)
.font(.title)
Group {
Text("100").bold()
+ Text(" SWIFTUI ")
.font(Font.system(size: 60))
.fontWeight(.ultraLight)
.foregroundColor(.blue)
.baselineOffset(-12) // Negative numbers make it go down
+ Text ("VIEWS").bold()
}
}
}
}
www.bigmountainstudio.com 266
Text
Layout Priority
Text("Text")
.font(.largeTitle)
Text("Layout Priority")
.font(.title)
.foregroundColor(.gray)
Image("LayoutPriority")
Text("Layout priority controls which view will get truncated last. The higher the priority, the
last it is in line to get truncated.")
.font(.title)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
.layoutPriority(2) // Highest priority to get the space it needs
Text("The text view above got truncated because its layout priority is zero (the default). This
text view has a priority of 1. The text view on top has a priority of 2.")
.font(.title)
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.padding()
.background(Color.green)
.layoutPriority(1) // Next highest priority
www.bigmountainstudio.com 267
Text
Custom Fonts
struct Text_CustomFont: View {
var body: some View {
VStack(spacing: 10) {
HeaderView("Text",
subtitle: "Custom Fonts",
desc: "Use a font that already exists on the system. If the font name
doesn't exist, it goes back to the default font.", back: .green, textColor: .white)
Text("Avenir Next")
.font(Font.custom("Avenir Next", size: 26))
Text("Gill Sans")
.font(Font.custom("Gill Sans", size: 26))
Text("Helvetica Neue")
.font(Font.custom("Helvetica Neue", size: 26))
www.bigmountainstudio.com 268
Text
Imported Fonts
struct Text_CustomFont: View {
var body: some View {
VStack(spacing: 20) {
Text("Text")
.font(.largeTitle)
Text("Imported Fonts")
.font(.title)
.foregroundColor(.gray)
Text("Use the Font.custom() function to set imported fonts you added to your
project.")
...
Text("Hello, World!")
.font(Font.custom("Nightcall", size: 60))
.padding(.top)
}
}
}
In order for this to work, you have to add the font file to your project and be sure to have the font file
target your project. Then you need to add the font file name to the Info.plist under the “Fonts provided
by application” key:
www.bigmountainstudio.com 269
Text
Text("Hello, World!")
.font(.custom("Avenir Next Bold", size: 26,
relativeTo: .largeTitle))
Text("Hello, World!")
.font(.custom("Nightcall", size: 26,
relativeTo: .caption2))
}
.font(.title)
}
}
www.bigmountainstudio.com 270
iOS 14
TextEditor
Text
This is a push-out view. SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 271
TextField
In order to get or set the text in a TextField, you need to bind it to a variable. This variable is passed into the TextField s
initializer. Then, all you need to do is change this bound variable s text to change what is in the TextField. Or read the bound
variable s value to see what text is currently in the TextField.
www.bigmountainstudio.com 272
’
’
’
TextField
Introduction
struct TextField_Intro : View {
@State private var textFieldData = ""
www.bigmountainstudio.com 273
TextField
Text("You can supply title text (placeholder/hint text) through the first parameter
to let the user know the purpose of the text field.")
.frame(maxWidth: .infinity).padding()
.background(Color.orange)
Group {
TextField("Here is title text", text: $textFieldData)
.textFieldStyle(.roundedBorder)
www.bigmountainstudio.com 274
TextField
Text Alignment
struct TextField_Alignment: View {
@State private var textFieldData1 = "Leading"
@State private var textFieldData2 = "Center"
@State private var textFieldData3 = "Trailing"
Group {
TextField("Leading", text: $textFieldData1)
.textFieldStyle(.roundedBorder)
.multilineTextAlignment(.leading) // Default
www.bigmountainstudio.com 275
TextField
Text("Notice this also changes the placeholder or hint text in the text field.")
.frame(maxWidth: .infinity)
.padding()
.background(Color.orange)
}.font(.title)
}
}
www.bigmountainstudio.com 276
TextField
Customizing Colors
struct TextField_Customizing : View {
@State private var textFieldWithText = "With Text"
@State private var textFieldNoText = ""
@State private var withOutline = "With Outline"
www.bigmountainstudio.com 277
TextField
Border
struct TextField_Border: View {
@State private var textFieldData = ""
Group {
TextField("Data", text: $textFieldData)
.padding(5)
.border(Color.orange)
www.bigmountainstudio.com 278
TextField
Group {
// First TextField
ZStack(alignment: .leading) {
// Only show custom hint text if there is no text entered
if textFieldData.isEmpty {
Text("Enter name here").bold()
.foregroundColor(Color(.systemGray4))
}
TextField("", text: $textFieldData)
}
.padding(EdgeInsets(top: 4, leading: 10, bottom: 4, trailing: 10))
.overlay(
// Add the outline
RoundedRectangle(cornerRadius: 8)
.stroke(Color.orange, lineWidth: 2))
// Second TextField
ZStack(alignment: .leading) {
if textFieldData.isEmpty {
Text("Email Address").italic()
www.bigmountainstudio.com 279
TextField
www.bigmountainstudio.com 280
TextField
Custom Composition
@State private var textFieldData = ""
...
VStack {
HStack {
Image(systemName: "magnifyingglass").foregroundColor(.gray)
TextField("first name", text: $textFieldData)
Image(systemName: "slider.horizontal.3")
}
Divider()
}
.padding()
HStack {
Image(systemName: "envelope")
.foregroundColor(.gray).font(.headline)
TextField("email address", text: $textFieldData)
}
.padding()
.overlay(RoundedRectangle(cornerRadius: 8).stroke(Color.gray, lineWidth: 1))
.padding()
HStack {
TextField("country", text: $textFieldData)
Button(action: {}) {
Image(systemName: "chevron.right").padding(.horizontal)
}
.accentColor(.orange)
}
.padding()
.overlay(Capsule().stroke(Color.gray, lineWidth: 1))
.padding()
www.bigmountainstudio.com 281
TextField
Keyboard Type
struct TextField_KeyboardType: View {
@State private var textFieldData = ""
Image(“KeyboardType")
Spacer()
}.font(.title)
}
}
www.bigmountainstudio.com 282
TextField
www.bigmountainstudio.com 283
TextField
.phonePad
www.bigmountainstudio.com 284
TextField
VStack(spacing: 10) {
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
Use width: 214
TextField("one time unique code", text: $code)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
.font(.title)
www.bigmountainstudio.com 285
TextField
Disable TextFields
struct TextField_Disabled: View {
@State private var lastName = "Moeykens"
@State private var city = "Salt Lake City"
@State private var disabled = false
Group {
TextField("Enter Last Name", text: $lastName)
TextField("Enter City", text: $city)
}
.disableAutocorrection(true)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
.disabled(disabled) // Don't allow to edit when disabled
.opacity(disabled ? 0.5 : 1) // Fade out when disabled
Spacer()
💡
}.font(.title)
}
}
www.bigmountainstudio.com 286
TextField
onEditingChanged
struct TextField_OnEditingChanged: View {
@State private var text = ""
@State private var isEditing = false
www.bigmountainstudio.com 287
TextField
iOS 15
Autocapitalization
struct TextField_Autocapitalization: View {
@State private var textFieldData1 = ""
When a user starts typing into a TextField, the
@State private var textFieldData2 = "" first word in each sentence is always
@State private var textFieldData3 = "" capitalized. You can change this behavior with
@State private var textFieldData4 = "" the textInputAutocapitalization modifier.
var body: some View {
VStack(spacing: 50) {
Text("Words")
TextField("First & Last Name", text: $textFieldData1)
.textInputAutocapitalization(.words)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
Text("Sentences (default)")
TextField("Bio", text: $textFieldData2)
.textInputAutocapitalization(.sentences)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
Text("Never")
TextField("Web Address", text: $textFieldData3)
.textInputAutocapitalization(.never)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
Text("Characters")
TextField("Country Code", text: $textFieldData4)
.textInputAutocapitalization(.characters)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
}
}
}
www.bigmountainstudio.com 288
TextField
HeaderView("TextField",
subtitle: "Keyboard Safe Area",
desc: "TextFields will automatically move into view when the keyboard
appears. The keyboard adjusts the safe area so it will not cover views.",
back: .orange)
.font(.title)
}
}
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 289
Toggle
The Toggle is a switch that can either be on or off. Much like other controls, you need to bind it to a variable. This variable is
passed into the Toggle s initializer. Then, all you need to do is change this bound variable s value to change the Toggle s
state on or off. Or read the bound variable s value to see what state the Toggle is currently in.
www.bigmountainstudio.com 290
’
’
’
’
Toggle
Introduction
struct Toggle_Intro : View {
@State private var isToggleOn = true
💡
Toggle("Night Mode", isOn: $isToggleOn)
.padding()
.accentColor(Color.red)
VStack {
Text("Turn Alarm On?")
.foregroundStyle(.white)
Toggle("Turn this alarm on", isOn: $isToggleOn)
.labelsHidden() // Hides the label/title
}
.padding(25)
.background(Color.blue)
.cornerRadius(20)
}
.font(.title)
}
}
www.bigmountainstudio.com 291
Toggle
Group {
Toggle(isOn: $isToggleOn) {
Text("Red")
Image(systemName: "paintpalette")
}
.toggleStyle(SwitchToggleStyle(tint: Color.red))
Toggle(isOn: $isToggleOn) {
Text("Orange")
Image(systemName: "paintpalette")
}
.toggleStyle(SwitchToggleStyle(tint: Color.orange))
}
.padding(.horizontal)
}
.font(.title)
}
}
www.bigmountainstudio.com 292
Toggle
Tint iOS 15
Group {
Toggle(isOn: $isToggleOn) {
Text("Red")
Image(systemName: "paintpalette")
}
.tint(.red)
Toggle(isOn: $isToggleOn) {
Text("Orange")
Image(systemName: "paintpalette")
}
.tint(.orange)
}
.padding(.horizontal)
}
.font(.title)
}
}
www.bigmountainstudio.com 293
Toggle
ToggleStyle iOS 15
Toggle(isOn: $toggleOn) {
Image(systemName: "heart")
.symbolVariant(toggleOn ? .fill : .none)
}
.toggleStyle(.button)
Notice when the toggleStyle is button and
}
.font(.title)
it is in the on state, the whole button
} becomes filled.
}
www.bigmountainstudio.com 294
ADDITIONAL CHAPTERS
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
296
PAINTS
Covered in the SwiftUI Views Mastery book.
Includes: AngularGradient, ImagePaint, LinearGradient and RadialGradient with the many examples
of how they work when applied to different views.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
297
CONTROLS MODIFIER Covered in the SwiftUI Views Mastery book.
Includes: ActionSheet, Alert, ContextMenu, Sheet (Modals), Popover, Custom Popups and the StatusBar
Hidden modifier with the many examples of how they work when used with different views.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
www.bigmountainstudio.com 298
LAYOUT MODIFIERS Covered in the SwiftUI Views Mastery book.
Includes: AspectRatio, Background, EdgesIgnoringSafeArea, FixedSize, Frame, Hidden,
LayoutPriority, Offset, Overlay, Padding, Position, ScaleToFill, ScaleToFit, and zIndex with the many
examples of how they work when used with different views and modifiers.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
299
EFFECT MODIFIERS Covered in the SwiftUI Views Mastery book.
Includes: AccentColor, BlendMode, Blur, Border, Brightness, Clipped, ClipShape, ColorInvert,
ColorMultiply, ColorScheme, CompositingGroup, ContentShape, Contrast, CornerRadius,
DrawingGroup, ForegroundColor, Grayscale, HueRotation, LuminanceToAlpha, Mask, Opacity,
PreferredColorScheme, RotationEffect, Rotation3DEffect, Saturation, ScaleEffect, Shadow, and
TransformEffect with the many examples of how they work.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
300
CUSTOM STYLING Covered in the SwiftUI Views Mastery book.
Includes: ButtonStyle, DatePickerStyle, ListStyle, NavigationViewStyle, PickerStyle, TextFieldStyle,
ToggleStyle, Global Styling, View Modifiers and Styling Shapes with the many examples of how
they work when used.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
301
IMAGE MODIFIERS Covered in the SwiftUI Views Mastery book.
Includes: Interpolation, RenderingMode, Resizable, and Symbol ImageScale with the many
examples of how they work.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
302
GESTURES
Covered in the SwiftUI Views Mastery book.
Includes: Drag Gesture, On Long Press Gesture, Magnification Gesture, Rotation Gesture, On Tap
Gesture, Exclusive Gesture, Simultaneous Gesture, Sequence Gesture and High Priority Gesture
with the examples of how they work when applied to different views.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
303
OTHER MODIFIERSCovered in the SwiftUI Views Mastery book.
These are new modifiers that SwiftUI introduced after iOS 13. They include: AllowsHitTesting,
Disabled, Preference and Redacted.
ဃ
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
304
IMPORTING VIEWS
Covered in the SwiftUI Views Mastery book.
Includes how to use the new views that came with the release of iOS 14:
VideoPlayer view in the AVKit and Map view in the MapKit.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
305
ACCESSIBILITY
Covered in the SwiftUI Views Mastery book.
Learn how to include accessibility to enable things like voice over and guidance to the disabled.
SAVE 10% AND UNLOCK THE BOOK TODAY FOR ONLY $55 $49.50!
306
THE END
I hope you enjoyed this free SwiftUI Views Quick Start!
This was just the beginning of a larger book.
@BigMtnStudio @BigMtnStudio
Stay up-to-date on what I m learning and working on. These are the Do you prefer hanging out in Instagram? Then follow and get bite-
most real-time updates you will find. sized chunks of dev info.
308
’
’
’
MORE FROM ME
BMS_10
Because you got this book you get an introductory discount of 10% off everything in the store. This is to encourage you to continue your
SwiftUI journey and keep getting better at your craft. Enter the code above on checkout or click the button below. 👇
ACTIVATE DISCOUNT
(Note: You should have gotten an email with this coupon code too. Make sure you opt-in for even better discounts through sales in the
future. Go here for instructions on how to do this.)
310
More From Me
SwiftUI Essentials
ARCHITECTING SCALABLE & MAINTAINABLE SWIFTUI APPS
www.bigmountainstudio.com 311
’
More From Me
Over 1,000 pages of SwiftUI Find out how to implement action sheets, modals, popovers
Over 700 screenshots/videos showing you what you can do and custom popups
so you can quickly come back and reference the code Master all the layout modifiers including background and
Learn all the ways to work with and modify images overlay layers, scaling, offsets padding and positioning
See the many ways you can use color as views How do you hide the status bar in SwiftUI? Find out!
Discover the different gradients and how you can apply them This is just the tip of the mountain!
www.bigmountainstudio.com 312
More From Me
www.bigmountainstudio.com 313
’
More From Me
www.bigmountainstudio.com 314
More From Me
www.bigmountainstudio.com 315
More From Me
www.bigmountainstudio.com 316
’
THANK YOU
I hope you have enjoyed this book If you find anything wrong or have Found a way to create a cool UI? I d
as your visual quick start reference suggestions for improvement, be super interested to see it!
guide. please let me know.
If you would like to write a positive
A lot of time and work went into this Email: review on how this book has helped
to make it as easy as possible for [email protected] you, I would love to hear that too!
you to use.
Direct Message me on Twitter:
@bigmtnstudio
www.bigmountainstudio.com 317
’
PARTNERING INFO
IT’S FREE TO PARTNER UP AND MAKE MONEY. JUST FOLLOW THESE 2-STEPS:
www.bigmountainstudio.com 318
SHARE THE LOVE
If you like this book and find it useful, I encourage you to share links to my products. I ll give you some effective sharing
tips on the next page. Here are some tips on what you can and cannot share.
www.bigmountainstudio.com 319
’
’
’
SHARING TIPS
If you have never been an affiliate before and want some tips to effectively share my products then read on!
www.bigmountainstudio.com 320
’
’