How to Make a Tab Bar View in SwiftUI

In this post we are going to take a look at how we can add a tab bar view to our SwiftUI app. Tab bar views are used to display a view when the tab item is selected. For this example we will simply have two tab views that will show a text view with a different background color. Let’s start by creating our example views that we will assign to our tab bar.

import SwiftUI
struct FirstView: View {
    var body: some View {
        ZStack {
            Color(.green)
            Text("First View")
                .font(.title)
        }.ignoresSafeArea()
    }
}
struct SecondView: View {
    var body: some View {
        ZStack {
            Color(.blue)
            Text("Second View")
                .font(.title)
                .foregroundColor(.white)
        }.ignoresSafeArea()
    }
}

As you can see we have created two views with just a text view and a color for the background. Now that we have our views setup we can go to our ContentView.swift file and make our tab bar view.

import SwiftUI
struct ContentView: View {
    var body: some View {
        TabView {
            FirstView()
                .tabItem {
                    Image(systemName: "1.circle.fill")
                    Text("First View")
                }
        
            SecondView()
                .tabItem {
                    Image(systemName: "2.circle.fill")
                    Text("Second View")
                }
        }
    }
}

As you can see in the example above all we needed to do was make a TabView and initialize our two views as a .tabItem. Inside of our .tabItem we added an image and the title to be displayed on our tab. Now if we run our application we should see our app look like the images below.

I hope this helps you on your next SwiftUI project.

Thanks for reading and happy coding!

How to Fetch JSON Data from APIs in SwiftUI

In this post we are going to take a look at how we can get JSON data from an API and show it in a list view in SwiftUI. Let’s jump right in a get started by creating a new SwiftUI project.

In this project we are going to be using the JSONPlaceholder API. JSONPlaceholder is a free to use fake REST API for testing and prototyping.

We will be fetching our data from the https://jsonplaceholder.typicode.com/posts/1/comments URL.

Now in our Xcode project we will create a model file and name it Comments. This will be our model for the data we are going to want to show in our list view.

import SwiftUI

struct Comments: Codable, Identifiable {
    let id = UUID()
    let name: String
    let email: String
    let body: String
    
}

In the code above we made a simple struct that conforms to the Codable and Identifiable protocols. Codable is used for decoding and encoding the JSON data we get from our API call. Identifiable is used to help us make a unique identifier for our Comments object so our app can keep track of it. In our example it helps us to keep track of our comments and display them in the right order for our list view. We also have added the name, email, and body properties that will be set to the JSON data we get back from our API call.

Next we will add a new file where we will create the call to our API to get our JSON data. Let’s start by creating a new file and naming it commentViewModel. Then we will add the following code to our commentViewModel file.

import Foundation

class apiCall {
    func getUserComments(completion:@escaping ([Comments]) -> ()) {
        guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1/comments") else { return }
        
        URLSession.shared.dataTask(with: url) { (data, _, _) in
            let comments = try! JSONDecoder().decode([Comments].self, from: data!)
            print(comments)
            
            DispatchQueue.main.async {
                completion(comments)
            }
        }
        .resume()
    }
}

Above all we did was create a class called apiCall and added a function called getUserComments(). In our getUserComments() function we first make a guard let statement on our url variable. This is to check to make sure we have a valid URL otherwise the function will stop there and not execute the rest of the code.

Next we use URLSession to make our call to get the data from the URL. Inside of our URLSession closure we create a new variable called comments and we assign the decoded JSON to our variable. Then we use DispatchQueue to make sure we are running this API call on the main thread and not a background thread of our app. On completion of retrieving our data we then assigns the data to our comments variable. Lastly we can’t forget the .resume() function at the end of your URLSession curly brace. If you forget this the function will never run the API call to the URL.

Now that we have our view model setup lets go into ContentView file and add the following code to our file.

import SwiftUI

struct ContentView: View {
    //1.
    @State var comments = [Comments]()
    
    var body: some View {
        NavigationView {
            //3.
            List(comments) { comment in
                VStack(alignment: .leading) {
                    Text(comment.name)
                        .font(.title)
                        .fontWeight(.bold)
                    Text(comment.email)
                        .font(.subheadline)
                        .fontWeight(.bold)
                    Text(comment.body)
                        .font(.body)
                }
                
            }
            //2.
            .onAppear() {
                apiCall().getUserComments { (comments) in
                    self.comments = comments
                }
            }.navigationTitle("Comments")
        }
    }
}
  1. First we created a @State variable that takes in an array of our Comments model.
  2. Next we added the .onAppear() function. This is were we make our call to our API to get our data and then set it to the comments variable we just created.
  3. Then in our list view we pass in the data that we have in our Comments array

Now we can go and run our app. We should see something like the image below.

Thats all we need to fetch and show JSON data in SwiftUI. Thanks for reading!

Happy Coding!

data numbers GIF

How to Make a Phone Call using SwiftUI

Making a phone call from a SwiftUI app is easy and only takes a few lines of code to implement. All we need to do is setup a button that will open the phone app and make a phone call with a phone number we pass in.

Let’s look at some code below to see what we need to implement this.


struct ContentView: View {

    var phoneNumber = "718-555-5555"

    var body: some View {
        VStack {
            Button(action: {
                let phone = "tel://"
                let phoneNumberformatted = phone + phoneNumber
                guard let url = URL(string: phoneNumberformatted) else { return }
                UIApplication.shared.open(url)
               }) {
               Text(phoneNumber)
                .foregroundColor(.blue)
            }
        }
    }
}

In the example above we first create a string variable with the phone number we would like to use. Next we create a button and within the action of our button we format the phone number to our URL. The “tel://” is the url needed to tell our device to open the phone app and make a call. (We can use the same code above to open other apps on our device. For example if we wanted to open the mail app we just need to replace the url with messages:// instead of tel://)

Next we have a guard let statement to check to see if we have a formatted phone number. Then we use UIApplication to open the phone app and make a call using the url with the phone number we passed in. Lastly we set our button label to show the phone number we want to call.

(Side note: We will need to run this on a device to test because the simulator can not make phone calls.)

That is all that we need to make a phone call from our SwiftUI app. Hope this helps you on your next SwiftUI project!

Thanks for reading!

☎️📱🤳Happy coding ☎️📱🤳

What’s the Difference between @ObservedObject and @StateObject

@StateObject and @ObservedObject are very similar in that they both keep track of an objects state. The difference is @StateObject is owned by the view it was created in where as @ObservedObject is owned by another view.

An example of when to use @ObservedObject is to keep track of external classes so the view can be updated when a change occurs. We would want to use an @ObservedObject for something like fetching new data from an API or a database.

We want to use @StateObject when we want the view to keep track of its own objects state. A example of how we would use @StateObject is if we had something like a number counter in a view and we wanted to keep track of the count as the numbers changed.

I hope this helps you better understand the difference between when to use @ObservedObject and @StateObject.

For a deeper dive into @StateObject vs @ObservedObject checkout these great articles by Donny Wals and Swapnanil Dhol.

Thanks for reading and happy coding 👨🏻‍💻👨🏻‍💻👨🏻‍💻

How to Use Link to Open Webpages in SwiftUI

SwiftUI makes opening a URL with your default web browser super easy with the Link view. All you need to do is give it a title and a destination URL. Let us take a look at the example below.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Link("Swift Tom!", destination: URL(string: "https://www.swifttom.com/")!)
        
    }
}

As you can see in our example we are added a title of “Swift Tom!” and our destination URL swifttom.com. If we go and run this code in our simulator we will see our Link button that when it is tapped will bring us to my swifttom.com webpage.

Hope you enjoyed this quick look at how we can use Link views to our SwiftUI project.

For more on how to use Link views we can check out Apple’s Documentation here.

🔗🔗🔗 Happy Coding! 🔗🔗🔗

How to Blur a View in SwiftUI

SwiftUI makes it easy to add a blur effect to any view. All we need to do is add the .blur() modifier to our view. Let’s see how we can apply this by looking at the example below.

 import SwiftUI
import PlaygroundSupport
struct ContentView: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            Text("Hello Tom")
        }
    }
}
PlaygroundPage.current.setLiveView(ContentView()) 

As you can see in the example we have a ZStack with a green background and a text view. If we want to add a blur effect to our text view all we need to do is add the .blur() modifier to it.

 import SwiftUI
import PlaygroundSupport
struct ContentView: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            Text("Hello Tom")
                .blur(radius: 1.5)
        }
    }
}
PlaygroundPage.current.setLiveView(ContentView()) 

As you can see above we added the blur effect with a 1.5 radius to our “Hello Tom” text view. It is good to know that the higher the radius the more blurry the view will appear.

Thanks for reading and happy coding!

How to Use SF Symbols in a SwiftUI project

SF Symbols are set of over 2,000 symbols created by Apple for developers to use in there apps. SF Symbols are dynamic. This means that they will automatically align with the size and weight of text in our app. We can use these symbols for almost anything but they are most commonly used in toolbars, menus, and navigation bars.

We can use SF Symbols in our project by using the Image(systemName:) image view. In the system name parameter we will add the string of the SF Symbol we want to use.

Image(systemName: “cloud.sun.fill”)

As you can see in the example above we added the “cloud.sun.fill” SF Symbol to our image view.

We can also customize SF Symbols. If we want to change something like the color of our SF Symbol all we need to do is change the .foregroundColor(). We can also change the size of our symbol by changing the .font size.

Image(systemName: “cloud.heavyrain.fill”)
.foregroundColor(.green)
.font(.title)

That was a quick look at how we can add SF Symbols to our SwiftUI projects. For more info checkout Apples Human Interface Guidelines on how you should use SF Symbols in our projects.

Thanks for reading and Happy Coding!

Access Control in Swift

What is Access Controls in Swift? According to the documentation “Access control restricts access to parts of your code from code in other source files and modules. This feature enables you to hide the implementation details of your code, and to specify a preferred interface through which that code can be accessed and used.” We can implement access controlS by adding five different types of modifiers to our code. These modifiers are:

  • Public: Which means anyone can read and write to this property.
  • Internal: This is the default access control for any property we create. This allows us access within the same module.
  • File Private: Like the name says, this modifier allows us to only access this property within the same file.
  • Private: This is the most restrictive. This only allows access within the current enclosing it is being used in.
  • Open: This is the most unrestricted. This property can be accessed from anywhere and other developers can subclass it and/or override it.

If you would like a deeper dive into Access Control check out the Swift Documentation on it.

Thanks for reading and I hope this gives you a better understand of when to use Access Controls in Swift.

Happy Coding!!!

How to Make Static and Dynamic Home Screen Quick Actions in SwiftUI

Home screen quick actions are shortcuts for users to navigate into different parts of our app. In this post we are going to see how we can add these quick actions into our SwiftUI project. The two different types of quick actions we can use is static quick actions and dynamic quick actions. Let’s start by taking a look at how we can add static quick actions to our project.

As the name implies static quick actions do not change. If we want to add static quick actions to our project we will need to implement it in our info.plist. If we right click on the info.plist and go to >  Open As > Source Code and at the bottom before the last </dict> add the following code below.

	<key>UIApplicationShortcutItems</key>
	<array>
		<dict>
			<key>UIApplicationShortcutItemType</key>
			<string>AddAction</string>
			<key>UIApplicationShortcutItemIconType</key>
			<string>UIApplicationShortcutIconTypeAdd</string>
			<key>UIApplicationShortcutItemTitle</key>
			<string>Add</string>
			<key>UIApplicationShortcutItemSubtitle</key>
			<string>Add Item</string>
		</dict>
	</array>

In the code above we are using UIApplicationShortcutItems to create an add button for our quick action shortcuts. Our shortcut items can be found inside an array of a dictionary. In each dictionary a UIApplicationShortcutItemType and UIApplicationShortcutItemTitle are needed to make our static shortcut. UIApplicationShortcutItemType is a string that represents what kind of quick action we want in our app. UIApplicationShortcutItemTitle is the title or name of our quick action button.

If you want to learn more about UIApplicationShortcutItem‘s check out the Apple documentation.

Now if you run the app and then go to the home screen we can test our quick action. On the home screen if we tap and hold on our app icon we should see the “Add” quick action button pop up on our home screen.

Now that we made a static quick action let’s move on to adding a dynamic quick action button.

To make a dynamic quick action we will need to add them in the App struct also known as the entry point of our app. This file can be located in the navigator and is usually named after your project name followed by the word App. In this example it will be in the QuickActionSwuiftUIBlogApp.swift file.

The reason we need to create our quick action buttons in this file is because these buttons need to be made at specific point in the apps life cycle. Apples documentation recommends that we create dynamic quick actions when the app is moving to the background.

import SwiftUI

@main
struct QuickActionSwuiftUIBlogApp: App {
    @Environment(\.scenePhase) var lifeCycle
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: lifeCycle) { (newLifeCyclePhase) in
            switch newLifeCyclePhase {
            case .active :
                print("App is active")
            case .inactive:
                print("App is inactive")
            case .background:
                print("App is going to the Background")
                // This will add our dynamic quick actions when our app is sent to the background on our device
                addQuickActions()
            @unknown default:
                print("default")
            }
        }
    }
    
    func addQuickActions() {
        UIApplication.shared.shortcutItems = [
            UIApplicationShortcutItem(type: "Tweet", localizedTitle: "Tweet"),
            UIApplicationShortcutItem(type: "Call", localizedTitle: "Call"),
            UIApplicationShortcutItem(type: "Message", localizedTitle: "Message"),
            UIApplicationShortcutItem(type: "Saved", localizedTitle: "Saved"),
        ]
    }
}

As you can see in the code above we created some dynamic shortcuts buttons in our addQuickActions() function. We call the addQuickActions() function to make our dynamic buttons when our app goes into the background state. We know when our app goes to the background by using the .onChange modifier with our @Environment(\.scenePhase) var lifeCycle variable. For a deeper dive please check out the Apple documentation.

Now if we rerun our app and long press on our app icon we should see our static quick action button with our dynamic quick action buttons underneath. You may also notice that one of our quick buttons doesn’t show up in the quick action sheet. This is because Apple will only show a maximum of 4 quick actions at a time.

Next we will go back into our addQuickActions() function and add some more code.

    func addQuickActions() {
        var tweetuserInfo: [String: NSSecureCoding] {
                    return ["name" : "tweet" as NSSecureCoding]
                }
                var calluserInfo: [String: NSSecureCoding] {
                    return ["name" : "call" as NSSecureCoding]
                }
                var messageuserInfo: [String: NSSecureCoding] {
                    return ["name" : "message" as NSSecureCoding]
                }
                var saveduserInfo: [String: NSSecureCoding] {
                    return ["name" : "saved" as NSSecureCoding]
                }
        
        UIApplication.shared.shortcutItems = [
            UIApplicationShortcutItem(type: "Tweet", localizedTitle: "Tweet", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .compose), userInfo: tweetuserInfo),
            UIApplicationShortcutItem(type: "Call", localizedTitle: "Call", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .audio), userInfo: calluserInfo),
            UIApplicationShortcutItem(type: "Message", localizedTitle: "Message", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .message), userInfo: messageuserInfo),
            UIApplicationShortcutItem(type: "Saved", localizedTitle: "Saved", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .love), userInfo: saveduserInfo),
        ]
    }

The example above will help us to identify each quick action button with a name key. This will allow us to know which of our quick actions was pressed this way we can have our app react according to what quick action the user has tapped. We will attach these new variables we created to the userInfo parameter of our UIApplicationShortcutItem. Above we also added icons to the shortcut items so we don’t just have dots as icon placeholders.

Now let’s add two global variables above our @main in our App file. These variables will help us to pass our users input along to different areas of our app depending on which quick action we press.

var shortcutItemToHandle: UIApplicationShortcutItem?
let quickActionSettings = QuickActionSettings()

Next we will need to add two more functions below our addQuickActions() function.

    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
            if let shortcutItem = options.shortcutItem {
                shortcutItemToHandle = shortcutItem
            }
            
            let sceneConfiguration = UISceneConfiguration(name: "Custom Configuration", sessionRole: connectingSceneSession.role)
            sceneConfiguration.delegateClass = CustomSceneDelegate.self
            
            return sceneConfiguration
        }
    }

    class CustomSceneDelegate: UIResponder, UIWindowSceneDelegate {
        func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
            shortcutItemToHandle = shortcutItem
        }
    }

In the code above we added an Appdelegate method and a Scenedelegate method to handle what happens to our quick action buttons at different parts of the life cycle of our app. What these two class methods are doing is handling if the app is closed we want it to open our application and if our app is in the background to handle a quick action if the user taps on it.

Now that we have set up our quick action buttons we will want them to do something when a user taps on them. We want the user to be able to navigate to the specific section they tapped on in the home screen shortcut. This means that in our newLifeCyclePhase switch statement in our .active case we will need to perform an action. Let’s take a look at how we implement this in the code below.

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(quickActionSettings)
        }
        .onChange(of: lifeCycle) { (newLifeCyclePhase) in
            switch newLifeCyclePhase {
            case .active :
                print("App is active")
                guard let name = shortcutItemToHandle?.userInfo?["name"] as? String else { return }
            case .inactive:
                print("App is inactive")
            case .background:
                print("App is going to the Background")
                // This will add our dynamic quick actions when our app is sent to the background on our device
                addQuickActions()
            @unknown default:
                print("default")
            }
        }
    }

Above we added a guard let variable to our .active case. This will check to see if we have a name attached to the button the user pressed on the quick action shortcuts.

Now that we set that up we will go into the ContentView.swift and we are going to make a simple list view that will correspond to our quick action dynamic buttons. This will also be where we setup a observable variable to see which button has been pressed from our App file and react by bringing our user to that view in the app.

Our ContentView.swift file should have the following code in it.

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var quickActionSettings: QuickActionSettings
    @State var selectedAction: Int?

    var body: some View {
            NavigationView {
                List {
                    ForEach(0..<allQuickActions.count) { index in
                        NavigationLink(destination: DetailView(name: allQuickActions[index].name), tag: allQuickActions[index].tag, selection: $quickActionSettings.quickAction) {
                            Text(allQuickActions[index].name)
                        }
                    }
                }
                .listStyle(SidebarListStyle())
                .navigationBarTitle("Quick Actions")
            }
        }
    
}

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

    struct QuickActionModel : Identifiable {
        let id = UUID()
        let name: String
        let tag: QuickActionSettings.QuickAction
    }

    let allQuickActions = [
        QuickActionModel(name: "Tweet", tag: .details(name: "tweet")),
        QuickActionModel(name: "Call",tag: .details(name: "call")),
        QuickActionModel(name: "Message", tag: .details(name: "message")),
        QuickActionModel(name: "Saved", tag: .details(name: "save")),
    ]

As you can see in the example we added a @EnvironmentObject to track which quick action our user has tapped from our quick actions on the home screen. We also setup a simple list view with all of our dynamic quick action buttons. We created a QuickActionModel struct with a name and a tag and created an array of quick actions so that we can segue to the detail view depending on which quick action was tapped.

Next we will need to make a new SwiftUI file called DetailView. In this file add the following code to make a simple view for our list view buttons to segue too. This detail view will just show the name of the button we selected.

import SwiftUI

struct DetailView: View {
    var name: String
    
    var body: some View {
        Text("\(name)!")
            .navigationBarTitle(name)
    }
}

Now we will make another swift file and name this one QuickActionSettings. This will be our observable object so we can keep track of which quick action was pressed.

import Foundation

class QuickActionSettings: ObservableObject {
    
    enum QuickAction: Hashable {
        case home
        case details(name: String)
    }
    
    @Published var quickAction: QuickAction? = nil
}

Here we are using a QuickAction enum to see if the name value changes. If it does change it will trigger our navigation link in our content view to segue to the quick action the user has tapped.

Lastly let’s go back to our App file and add our .enviormentObject to our ContentView() in our WindowGroup like below.

WindowGroup {
            ContentView()
                // We will use this modifier below to pass along which quick action that was pressed
                .environmentObject(quickActionSettings)
        }

We also need to update our code inside of our .active case. Here we will add another switch statement that will check the names associated with our quick actions buttons. We will then take this name variable and pass it along our quickActionSettings.quickAction so the rest of our app can update. Our final QuickActionSwuiftUIBlogApp file should look like the code below.

import SwiftUI

let quickActionSettings = QuickActionSettings()
var shortcutItemToHandle: UIApplicationShortcutItem?

@main
struct QuickActionSwuiftUIBlogApp: App {
    @Environment(\.scenePhase) var lifeCycle
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                // We will use this modifier below to pass along which quick action was pressed
                .environmentObject(quickActionSettings)
        }
        .onChange(of: lifeCycle) { (newLifeCyclePhase) in
            switch newLifeCyclePhase {
            case .active :
                print("App is active")
                guard let name = shortcutItemToHandle?.userInfo?["name"] as? String else { return }
                switch name {
                               case "tweet":
                                   print("tweet is selected")
                                   quickActionSettings.quickAction = .details(name: name)
                               case "call":
                                   print("call is selected")
                                   quickActionSettings.quickAction = .details(name: name)
                               case "message":
                                   print("message is selected")
                                   quickActionSettings.quickAction = .details(name: name)
                               case "saved":
                                   print("saved is selected")
                                   quickActionSettings.quickAction = .details(name: name)
                               default:
                                   print("default ")
                               }
            case .inactive:
                print("App is inactive")
            case .background:
                print("App is going to the Background")
                // This will add our dynamic quick actions when our app is sent to the background on our device
                addQuickActions()
            @unknown default:
                print("default")
            }
        }
    }
    
    func addQuickActions() {
        var tweetuserInfo: [String: NSSecureCoding] {
                    return ["name" : "tweet" as NSSecureCoding]
                }
                var calluserInfo: [String: NSSecureCoding] {
                    return ["name" : "call" as NSSecureCoding]
                }
                var messageuserInfo: [String: NSSecureCoding] {
                    return ["name" : "message" as NSSecureCoding]
                }
                var saveduserInfo: [String: NSSecureCoding] {
                    return ["name" : "saved" as NSSecureCoding]
                }
        
        UIApplication.shared.shortcutItems = [
            UIApplicationShortcutItem(type: "Tweet", localizedTitle: "Tweet", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .compose), userInfo: tweetuserInfo),
            UIApplicationShortcutItem(type: "Call", localizedTitle: "Call", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .audio), userInfo: calluserInfo),
            UIApplicationShortcutItem(type: "Message", localizedTitle: "Message", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .message), userInfo: messageuserInfo),
            UIApplicationShortcutItem(type: "Saved", localizedTitle: "Saved", localizedSubtitle: "", icon: UIApplicationShortcutIcon(type: .love), userInfo: saveduserInfo),
        ]
    }
    
    class AppDelegate: NSObject, UIApplicationDelegate {
        func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
            if let shortcutItem = options.shortcutItem {
                shortcutItemToHandle = shortcutItem
            }
            
            let sceneConfiguration = UISceneConfiguration(name: "Custom Configuration", sessionRole: connectingSceneSession.role)
            sceneConfiguration.delegateClass = CustomSceneDelegate.self
            
            return sceneConfiguration
        }
    }

    class CustomSceneDelegate: UIResponder, UIWindowSceneDelegate {
        func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
            shortcutItemToHandle = shortcutItem
        }
    }
}

If we test our code on our home screen we should be able to long press our icon and if we tap one of the dynamic quick action buttons it will open our app and navigate to that specific section of our app.

That is all you need to make home screen quick action shortcuts in SwiftUI.

All the code can be found here on my Github.

I hope this helped you add quick actions to your next SwiftUI project.

Happy Coding!

How to Make a Expandable Button in SwiftUI

In this post we are going to learn how to make a SwiftUI button that expands out to show more button options. Below is an example of what our button will look like when we are finished.

Let’s get started by creating a new SwiftUI project.

In our project let’s add a new SwiftUI file and name it ExpandableButton. Inside of our ExpandableButton.swift file we will add the following code.

import SwiftUI

struct ExpandableButton: View {
    var body: some View {
        Button(action: {
                    print("Expandable button tapped!!!")
        }) {
            Image(systemName: "plus.circle.fill")
                .resizable()
                .frame(width: 75, height: 75)
                .foregroundColor(.green)

        }
        
    }
}

In the code above all we did was create a button and stylize it. Next we will need to wrap our button in a VStack so that when we add our menu buttons they will appear above our expandable button.

import SwiftUI

struct ExpandableButton: View {
    var body: some View {
        VStack {
            Button(action: {
                        print("Expandable button tapped!!!")
            }) {
                Image(systemName: "plus.circle.fill")
                    .resizable()
                    .frame(width: 75, height: 75)
                    .foregroundColor(.green)

            }
        }
        
    }
}

Now let’s create our menu buttons in a new SwiftUI file. We will name this file MenuButtons and we will add the following code to it.

import SwiftUI

struct MenuButtons: View {
    var buttonImage: String
    
    var body: some View {
        Button(action: {
            print("Menu Button tapped")
            
        }) {
            ZStack {
                Circle()
                    .foregroundColor(.green)
                    .frame(width: 50, height: 50)
                
                Image(systemName: buttonImage)
                    .imageScale(.large)
                    .foregroundColor(.white)
                
            }
        }
    }
}

In the code above we made our menu buttons similar to how we created our expandable button. The only difference is that our menu buttons are slightly smaller and have a green circular background. We also added a buttonImage variable so that we can change the image that appears on our menu button.

Now that we have our menu button created let’s go back and add it to our ExpandableButton.swift file. First we will need to create a @State variable so that we can control when we show our menu buttons. In this example we will name are state property isExpanded and set it to false.

@State var isExpanded = false

Next we will add a conditional statement above our expandable button that will check if our button is expanded. If isExpanded returns true we will show our the menu buttons.

            if isExpanded {
                MenuButtons(buttonImage: "camera.fill")
                MenuButtons(buttonImage: "record.circle.fill")
                MenuButtons(buttonImage: "photo")
            }

In the action of our expandable button we will toggle our isExpanded property so that we can control when to show and hide our menu buttons. We’ll also add an animation so that when the expandable button is pressed our button will have a smooth transition. Our code should now look like the example below.

import SwiftUI

struct ExpandableButton: View {
    
    @State var isExpanded = false
    
    var body: some View {
        VStack {
            if isExpanded {
                MenuButtons(buttonImage: "camera.fill")
                MenuButtons(buttonImage: "record.circle.fill")
                MenuButtons(buttonImage: "photo")
            }
            
            Button(action: {
                print("Expandable button tapped!!!")
                isExpanded.toggle()
                
            }) {
                Image(systemName: "plus.circle.fill")
                    .resizable()
                    .frame(width: 75, height: 75)
                    .foregroundColor(.green)
            }
            
            
        }
        .animation(.spring())
    }
}

Now if we go and run our preview canvas we should see our button. If we go and tap our button then we should see our menu buttons pop up with an animation.

Thanks for reading! I hope this helps you in your next SwiftUI project.

All the code from this post can be found on my Github.

📱 Happy Coding! 💻