100 Days of SwiftUI Day 23

100 Days of SwiftUI – Day 23 -Views and Modifiers

We’ve arrived at day 23 of the 100 Days of SwiftUI. Yesterday, we had a very extensive recap for the Guess the Flag project, which really helped me learn a lot. Today, we’re immediately diving into the third project. This project will be a technique project, which is meant to help us understand how SwiftUI works behind the scenes. There’s won’t be a lot of complex code here, but a lot of valuable examples nonetheless. Let’s dive in!


Why modifier order matters in SwiftUI

When we add a modifier to a view in SwiftUI, we actually create a new view to which the modifier is applied. This continues on for every modifier we add. That’s why the order in which modifiers are added is important. For example, let’s say you want to color the entire background of a view.

    var body: some View {
        VStack{
            Button("Background color") {
                
            }
            .background(.indigo)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

Looking at the example above, you may expect the entire background to be colored in indigo. However, because we color the background first and only afterwards define the frame, this isn’t the case. If we switch them around though, it works just fine.

var body: some View {
        VStack{
            Button("Background color") {
                
            }
            .font(.largeTitle.bold())
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(.indigo)
        }
    }
}

Why does SwiftUI use “some View” for its view type?

It’s been a little while, but we’ve talked about opaque return types before. To recap:

In a nutshell, opaque return types allow us to make our code less complex by removing the need to specify exact return types when working with protocols. For example, instead of saying that we’ll return a specific vehicle like a bike or a car, we could just say that we’ll return some vehicle. We just don’t know which one yet or we don’t want to specify it yet. Swift will be able to determine by itself what type is expected by looking at the rest of our program.

Code Maverick

As it turns out, opaque return types aren’t only used with protocols. When you see var body: some View when starting a new SwiftUI project, it tells us that the body will return a view, we just don’t know what view yet. It could be a Text view, a VStack, a Button or a Color. Swift is smart enough to figure this out in the compiler and ensures the correct view is returned.

Environment modifiers

There will be times where you want to apply the same modifiers to multiple views. An easy way to do this is using an environment modifier. For example, if you have a VStack containing multiple Text views, you can give them all the same appearance in one go.

    var body: some View {
        VStack{
            Text("First text view")
            Text("Second text view")
            Text("Third text view")
            Text("Fourth text view")
        }
        .font(.largeTitle)
    }

Conditional modifiers

It’s common to only apply a modifier once a certain condition is met. We can accomplish this with a ternary operator, which we learned about during day 5. Time sure does fly!

Just to jog our memory, a ternary operator consists of WTF. A what, the condition being checked, True, what to do if the condition being checked is true, and False, what to do if the condition is false.

struct ContentView: View {
    
    @State private var toggleColor = false
    
    var body: some View {
        VStack{
            Button("Change color") {
                toggleColor.toggle()
            }
           .foregroundColor(toggleColor ? .indigo : .teal)
        }
    }
}

Views as properties

It’s possible to store views in properties and call them in our layouts. Paul explains that this allows for more complex view hierarchies.

struct ContentView: View {
    
    let myView = Text("Hello!")
    let mySecondView = Text("Goodbye!")
    
    var body: some View {
        VStack{
            myView
            mySecondView
        }
        .font(.largeTitle)
    }
}

View composition

SwiftUI lets us break down big Views into smaller Views. This has multiple advantages, including a cleaner body and a better overview of our Views.

struct capsuleText: View {
    var text: String
    
    var body: some View {
        Text(text)
        .font(.caption)
        .foregroundColor(.white)
        .padding(5)
        .background(.black)
        .clipShape(Capsule())
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            capsuleText(text: "First")
            capsuleText(text: "Second")
            
            Text("Hello, World")
                .titleStyle()
        }
    }
}

Custom modifiers

Last up today are custom modifiers. A custom modifier can contain multiple modifiers and apply them to a single View. They also allow for their own stored properties to be used.

struct Watermark: ViewModifier {
    var text: String
    func body(content: Content) -> some View {
        ZStack(alignment: .bottomTrailing) {
            content
            
            Text(text)
                .font(.caption)
                .foregroundColor(.white)
                .padding(5)
                .background(.black)
        }
    }
}
struct ContentView: View {
    var body: some View {
        VStack {
           Color.blue
                .frame(width: 300, height: 200)
                .modifier(Watermark(text: "Code Maverick"))
        }
    }
}

And that’s it for day 23! Today, we wrap up this project with a review and a few challenges. Time to recharge, which is needed after todays heatwave. See you tomorrow!

Darryl

Hi! My name is Darryl and this is my personal blog where I write about my journey as I learn programming! You'll also find articles about other things that interest me including games, tech and anime.

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

100 Days of SwiftUI – Day 50

100 Days of SwiftUI – Day 28 – BetterRest Wrap Up

100 Days of SwiftUI – Day 63

100 Days of SwiftUI – Day 4 – Type Annotations