Tap Me!

Tap Me!

Level: Beginner-Intermediate

Hello guys, today we are going to create a reactive app, and you are going to learn a new thing called "Property Wrappers". 

As we all know that Apple loves structs and structs are immutable in Swift. So to overcome this issue, Apple invented a great thing called "Property Wrappers". 

Let's dive deep and understand what's going on.

Whenever a struct gets initialized, all the properties inside it should have some values. Since all the views created using SwiftUI are structs, the properties once initialized cannot be changed.

Now that we are building an interactive app, the User Interface (UI) needs to be updated accordingly. 

I'm going to demonstrate the problem and the resolution that Apple prefers by building this app.

No alt text provided for this image


So without further due, let's get started.

Open Xcode and create a new project named "Tap Me".

As the entry point for our app is ContentView.swift file, open it and start writing some code.

First of all, we are going to enclose our view inside a NavigationView and provide a title.

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            Text("Hello World")
                .navigationBarTitle(Text("Tap Me! App"))

        }
    }
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


User Interface building in SwiftUI is declarative and what we want is a Text and a Button to be one after other vertically.

So we will put them together in a "VStack" which is a vertical stack of Views.

There are three types of stacks.

  1. HStack (Horizontal Axis)
  2. VStack (Vertical Axis)
  3. ZStack (Normal Axis)

Let's break down the UI Components hierarchy we want to create our app.

  NavigationView
    VStack
      HStack
        Text
      Button


Now that we have all the components broken down, let's write it down.

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                HStack (spacing: 16) {
                    Text("Tapped")
                        .font(.subheadline)

                    Text("0")
                        .font(.largeTitle)

                    Text("times")
                        .font(.subheadline)
                }

                Button(action: {
                    //Button Tapped
                }) {
                    Text("Tap Me")
                        .font(.title)
                }
            }
            .navigationBarTitle(Text("Tap Me! App"))
        }
    }
}


Now that we have created the UI, it is still not alive. So, let us give it life by making it reactive.

Our goal is to increase the value of the counter by one on the button click. So we will need an instance variable which will keep track of the value of the counter.

var count = 0
  

Now we are going to write the definition for the "buttonTapped" function. 

func buttonTapped() {
    //TODO:- Increment the value of counter by 1
}


 As soon as I change the value of the counter variable, Swift starts complaining that "'self is immutable" which means that the properties inside a struct once initialized cannot be changed.

No alt text provided for this image

Here comes the "Property Wrapper" to show it's power.

There are several "Property Wrappers" in Swift 5 but what we are interested in this article is "@State".

@State var count = 0


So, I'll just be adding "@State" before the declaration of the counter variable and BOOM, the code compiled successfully.

No alt text provided for this image

So what is happening behind the stage? This is what Apple says.

SwiftUI manages the storage of any property you declare as a state. When the state value changes, the view invalidates its appearance and recomputes the body. Use the state as the single source of truth for a given view.
reference: https://developer.apple.com/documentation/swiftui/state


Probably you are scratching your heads right now saying "What the heck is The single source of truth". Believe me guys, the same thing happened with me too when I was just starting to learn SwiftUI. 

When an object which is responsible for the changes in a specific UI component, it should have a single reference.

The pictures below will make you understand the "State" better.

No alt text provided for this image
No alt text provided for this image
No alt text provided for this image

Now that the concept of "@State" is clear, let's get back to our app.

Now that our counter is working as we wanted, we also need a button to reset the value of the counter.

So let's create a "Button" with a few other lines of code and place it in the "NavigationBar".

import SwiftUI


struct ContentView: View {
    @State var count = 0

    var resetButton: some View {
        Button(action: {
            self.count = 0
        }) {
            Image(systemName: "arrow.clockwise.circle")
                .imageScale(.large)
        }
    }

    var body: some View {
        NavigationView {
            VStack {
                HStack (spacing: 16) {
                    Text("Tapped")
                        .font(.subheadline)

                    Text("\(count)")
                        .font(.largeTitle)

                    Text("times")
                        .font(.subheadline)
                }

                Button(action: {
                    self.buttonTapped()
                }) {
                    Text("Tap Me")
                        .font(.title)
                }
            }
            .navigationBarItems(trailing: resetButton)
            .navigationBarTitle(Text("Tap Me! App"))
        }
    }
    
    func buttonTapped() {
        self.count += 1
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Now that everything is in the right place, let's run and test our app and see what we've built.

You can checkout the GitHub Repo for this project here.

In this article, we have learnt the basics of Stacks, NavigationView, Button and Property Wrappers. 

I hope you guys liked this post and understood the concept of State Management.

Thanks, everyone. Have a great day.

要查看或添加评论,请登录

Dheeraj Bhavsar的更多文章

  • Fall in ?? with Recursion

    Fall in ?? with Recursion

    Hello everyone, in your journey of programming you would have used recursion at least once. Today, I want to introduce…

  • Generic Codables - Swift

    Generic Codables - Swift

    Hello everyone, I guess you all have faced this problem which I came across in the past few days and didn't found any…

  • Navigation and Networking in SwiftUI

    Navigation and Networking in SwiftUI

    Level: Intermediate-Advanced Hello everyone, today we are going to learn the basics of navigation, networking and image…

    1 条评论
  • Hello Swift UI vs Hello Flutter

    Hello Swift UI vs Hello Flutter

    Level: Beginner In the previous article, We've discussed Swift UI and we are going to compare Swift UI with Flutter…

    1 条评论
  • Hello Swift UI

    Hello Swift UI

    Level: Beginner Hello everyone, today we are going to create an application based on Swift UI. As a programmer, we all…

    1 条评论

社区洞察

其他会员也浏览了