SwiftUI Thinking

Yusuf Demirci
Innovance Blog

--

It’s been a while since SwiftUI has been on our backlog. As iOS Developers, we’ve had SwiftUI on our radar, waiting for the right moment to dive into it during our free time.

Here’s a highlight of SwiftUI just for you!

If you are looking for a starting point for SwiftUI, you are at the right place!

Common View Components and Their Properties

Similar to UIKit, some of the most used UI components exist in SwiftUI.

Text

Text is equivalent to UILabel.

Text("Hello World!")
.font(.title.bold())
.foregroundStyle(.blue)
Text

Button

As you guessed, Button is equivalent to UIButton.

Button {
print("Button Action")
} label: {
Text("Hello World!")
.font(.title.bold())
.foregroundStyle(.white)
.padding()
.background(.blue)
.clipShape(RoundedRectangle(cornerRadius: 16))
}
Button

Image

As you might expect, Image is equivalent to UIImageView.

Image(systemName: "house.fill")
.resizable()
.scaledToFit()
.foregroundStyle(.blue)
Image

TextField

TextField equals to UITextField.

TextField("placeholder", text: .constant(""))
.textFieldStyle(.roundedBorder)
TextField

HStack & VStack

When it comes to structuring the UI of your app, it’s essential to align views with one another.

In SwiftUI, there are two primary layout builders for this purpose: HStack and VStack.

These layout builders allow you to arrange views horizontally and vertically, respectively.

You can also combine them to achieve more complex layouts.

HStack

HStack aligns views horizontally.

HStack {
Text("Leading Text")
.font(.body.bold())
.foregroundStyle(.blue)

Text("Trailing Text")
.font(.caption.bold())
.foregroundStyle(.orange)
}
HStack

VStack

It aligns views vertically.

VStack {
Text("Top Text")
.font(.body.bold())
.foregroundStyle(.blue)

Text("Bottom Text")
.font(.caption.bold())
.foregroundStyle(.orange)
}
VStack

Relationship Between Views: Flexible UI with Spacer

Spacer is SwiftUI’s light but powerful component to build flexible UI.

As you’re aware, aligning one view to another using constant margins (leading, top, trailing, bottom) can be overly cumbersome.

HStack {
Text("Leading Text")
.font(.body.bold())
.foregroundStyle(.blue)

Spacer()

Text("Trailing Text")
.font(.caption.bold())
.foregroundStyle(.orange)
}
Spacer in HStack

When a Spacer is placed between two Texts in an HStack, it naturally pushes the Texts towards the edges as it is designed to do.

HStack {
Spacer()

Text("Leading Text")
.font(.body.bold())
.foregroundStyle(.blue)

Spacer()

Text("Trailing Text")
.font(.caption.bold())
.foregroundStyle(.orange)

Spacer()
Spacer()
}

I add one more Spacer before the Leading Text and two more Spacers after the Trailing Text.

More Spacers in HStack

When adding Spacers, the Leading Text is pushed away from its leading edge by one Spacer, while the Trailing Text is pushed away from its trailing edge by two Spacers.

As a result, the Trailing Text ends up farther away from the device edge compared to the Leading Text.

Working with Data List

Regarding the data list, SwiftUI has two options, List or Foreach.

List

List equals to UITableView in UIKit.

var numbers = [1, 2, 3, 4, 5]

List(numbers, id: \.self) { number in
Text("\(number)")
}
List

This is pure simple!

List also has some prepared UI such as divider, card-looking, etc.

Foreach

var numbers = [1, 2, 3, 4, 5]

VStack {
ForEach(numbers, id: \.self) { number in
Text("\(number)")
}
}
Foreach

The Foreach construct offers a leaner alternative to the List component. With Foreach, you have full control over building your list UI, resulting in a simpler and more customizable approach.

Updating UI with Observable Property

SwiftUI differs from UIKit by embracing the Declarative Programming approach.

In Declarative Programming, the UI observes changes in an Observable value or property.

Whenever the value changes, the UI dynamically adjusts to reflect the change.

SwiftUI’s fundamental property wrappers, State and Binding, enable observability:

State: Facilitates a one-way connection and is primarily used within the associated view.

Binding: Establishes a two-way connection and is utilized to transmit State properties to another view.

For now, let’s focus on only the State

@State var text: String = "Initial Text"

VStack(spacing: 32) {
Button {
text = "Edited Change"
} label: {
Text("Change Text")
.font(.title.bold())
.foregroundStyle(.white)
.padding()
.background(.blue)
.clipShape(RoundedRectangle(cornerRadius: 16))
}

Text(text)
.font(.body.bold())
.foregroundStyle(.blue)
}
State

The Change Text button action modifies the observable text property. As the UI is designed to listen to changes in the text property, it automatically updates itself. This functionality is made possible by the State property wrapper.

View

Every SwiftUI view is a struct that conforms to the View protocol.

Since structs do not allow class inheritance, SwiftUI views can only conform to protocols.

These characteristics necessitate adopting an approach that views in SwiftUI are standalone and unique.

In UIKit, it is common practice to create base classes for specific views like UIViewController and UITableViewController. While it may be challenging to break away from this habit, it is possible with a shift in mindset!

Useful Components

One of SwiftUI’s core principles is less code, more work.

There are some ready-to-use view components to make development easier.

Label

It is a mix of Image and Text in an HStack.

Label("I am a Label", systemImage: "house.fill")
Label

Picker

It is a combined version of UISegmentedControl and UIPickerView.

It has various styles such as wheel, inline, segmented, and palette.

let numbers = [1, 2, 3, 4, 5]
@State var selection: Int = 0

Picker("Select", selection: $selection) {
ForEach(numbers, id: \.self) { number in
Text("\(number)")
}
}
.pickerStyle(.inline)
Picker

Image Scale

Since SwiftUI’s inception, Apple has provided its image library, SF Symbols. You can effortlessly access these images from the library using the Image view.

Additionally, you have the flexibility to scale the image using the font function, similar to setting the font for a Text view.

Image(systemName: "house.fill")
.font(.largeTitle)

SwiftUI is a new way to develop projects in Apple’s environment.

You somehow adapt your thinking to SwiftUI’s way.

Once you can do that, the doors of SwiftUI will be open totally for you!

--

--