Sneh Pandya Exploring the horizon with a knack for product management. Co-host of the NinjaTalks podcast and community organizer at Google Developers Group. Explorer, adventurer, traveler.

Building forms with SwiftUI: A comprehensive guide

5 min read 1542

Building Forms In Swift UI Guide

One of the most significant advances for dev tools in recent years has been the arrival of SwiftUI, allowing developers to design and build user interfaces using declarative code.

SwiftUI currently supports only iOS 13 and newer. This tutorial requires Xcode 11 (or a later version) and we will be using Swift 5 throughout.

In this article, we will be building a form in SwiftUI together, so feel free to follow along with this tutorial at your own pace — let’s waste no time and get started!

Introduction to SwiftUI

SwiftUI is an innovative shift in Apple’s ecosystem. App building through declarative code of the same complexity — with a lot less code — enables developers to rapidly develop apps in iOS. With a much simpler and faster UI pattern, it employs features like dynamic type, Dark Mode, localization, and accessibility right away when you use SwiftUI.

SwiftUI is accessible on all platforms, including macOS, iOS, iPadOS, watchOS, and tvOS. Developers can spend more time writing code efficiently, making platform-specific features, focusing on the UI because of the time saved using SwiftUI — in short, its a very useful tool in my experience!

Moreover, the Apple ecosystem allows you to make use of SwiftUI and UIKit alongside each other. This is a great advantage for all iOS developers, making it easier to adapt to the new shift.

Setting up an Xcode project with SwiftUI

To begin, open Xcode and choose Create a new Xcode project from the menu.

When using iOS, choose Single View Apps. It’s time to name and describe your app. The Use SwiftUI option must be selected at the bottom. If you don’t click this option, Xcode will create the storyboard file for you.

Now, Xcode will automatically create a file named ContentView.swift, and it will show you a live preview of your code to the right-hand side, as shown below. If you have not yet seen the preview, just hit the Resume button inside the preview pane and, once the project is built, you’ll be able to see the preview.

With the new instant preview feature, you can input code and see the visual changes in real-time, making the whole programming experience faster and allowing you to see alterations as they happen.



To build a form using SwiftUI, we are going to develop the different UI elements. Let’s implement them one-by-one and get to understand them better.

Creating the text fields

Let’s begin with a simple implementation using the text labels and the text fields.

// swift
Text("Name").font(.headline)

The above line creates a label using the Text component and sets the value of that label as Name. In addition, the .font property sets its font type to headline. To create a text field with a placeholder, you need to write the code like this:

// swift
TextField(.constant(""), placeholder: Text("Enter your name"))

You need to tell the SwiftUI framework using a VStack and arrange both the components as desired in order to put the label above the text field. The below code snippet shows how to do this.

// swift
struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {

            Text("Name").font(.headline)
            TextField(.constant(""), placeholder: Text("Enter your name"))

        }
    }
}

Now that we have created the basic text field and label, let’s improve the look and feel.

// swift
struct ContentView : View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Name").font(.headline)
            TextField(.constant(""), placeholder: Text("Enter your name"))
                .padding(.all)
                .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
        }
    }
}

In the above code, we have added a .padding(.all) property, which gives padding to the text typed inside the text input field. In addition, the .background property allows you to define the background color of the text input field and set a cornerRadius of 8.0, for this example.

Next, let’s fix the spacing with the screen edges. To do so, you need to specify the .padding property to the VStack, which holds the elements within itself.

// swift
struct ContentView : View {

    @State var name: String = ""

    var body: some View {
        VStack(alignment: .leading) {
        Text("Name").font(.headline)
            TextField(.constant(""), text: $name, placeholder: Text("Enter your name"))
                .padding(.all)
                .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
        }
        .padding(.horizontal, 16)
    }
}

(Note: We have also added a State variable called name, to hold the value of text input)

Converting components to the form

To populate different UI components and views, it is more efficient to reuse them, instead of duplicating the code. A Form in SwiftUI is a container view which allows you to group controls used for data entry.

The above mentioned components can be coded with the Form as below.

// swift
struct ContentView: View {


    @State var name: String = ""

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Profile")) {
                    Text("Name").font(.headline)
                    TextField(.constant(""), text: $name, placeholder: Text("Enter your name"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                }
                .padding(.horizontal, 16)
            }
            .navigationBarTitle("Settings")
        }
    }
}

The above code allows you to specify the Form object inside a NavigationView. The Section allows you to create a separate section inside the Form view, which you can then label using the header property.

Creating the toggle

You have successfully created the first component in the form using SwiftUI! Let’s update your form by adding a Toggle to give an option to make the profile hidden:

// swift
struct ContentView: View {


    @State var name: String = ""
    @State var isHidden: Bool = false

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Profile")) {
                    Text("Name").font(.headline)
                    TextField(.constant(""), text: $name, placeholder: Text("Enter your name"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                    Toggle(isOn: $isHidden) {
                        Text("Hide account")
                    }
                }
                .padding(.horizontal, 16)
            }
            .navigationBarTitle("Settings")
        }
    }
}

The Toggle is added below the TextField, as shown in the code, which allows you to turn it on or off, and saves the value to be processed in the variable called isHidden, which you can access and update the business logic as required.

Creating a picker

You can select a desired value from a list of options using the SwiftUI Picker component. For a Picker to work properly, you must provide it with an array of options and a State variable that records which one was selected. Let’s create a Picker that allows us to store chosen preferences:

// swift
struct ContentView: View {


    @State var name: String = ""
    @State var isHidden: Bool = false
    @State var email: String = ""
    @State var receiveEmails: Bool = false
    @State private var index = 0
    var emailOptions = ["All", "Transactional", "Marketing"]

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Profile")) {
                    Text("Name").font(.headline)
                    TextField(.constant(""), text: $name, placeholder: Text("Enter your name"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                    Toggle(isOn: $isHidden) {
                        Text("Hide account")
                    }
                }
                .padding(.horizontal, 16)


                Section(header: Text("Emails")) {
                    Toggle(isOn: $receiveEmails) {
                        Text("Receive emails")
                    }
                    TextField(.constant(""), text: $email, placeholder: Text("Enter your email"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                    Picker(selection: $index, label: Text("Email types")) {
                        ForEach(0 ..< emailOptions.count) {
                            Text(self.emailOptions[$0])
                        }
                    }
                }
                .padding(.horizontal, 16)
            }
            .navigationBarTitle("Settings")
        }
    }
}

As you can see in the code, a new section named Emails is introduced, which has a Toggle to enable email notifications, a TextField to take email as an input, and a Picker component to select the type of email.

Creating a slider

Slider is a component that allows you to drag the selection on a line to choose a value from a range that has already been set. The UISlider in UIKit is similar to the Slider in SwiftUI.


More great articles from LogRocket:


You can define a slider like this:

// swift
struct ContentView: View {


    @State var name: String = ""
    @State var isHidden: Bool = false
    @State var email: String = ""
    @State var receiveEmails: Bool = false
    @State private var index = 0
    var emailOptions = ["All", "Transactional", "Marketing"]
    @State var volumeSliderValue: Double = 0

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Profile")) {
                    Text("Name").font(.headline)
                    TextField(.constant(""), text: $name, placeholder: Text("Enter your name"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                    Toggle(isOn: $isHidden) {
                        Text("Hide account")
                    }
                }
                .padding(.horizontal, 16)


                Section(header: Text("Emails")) {
                    Toggle(isOn: $receiveEmails) {
                        Text("Receive emails")
                    }
                    TextField(.constant(""), text: $email, placeholder: Text("Enter your email"))
                        .padding(.all)
                        .background(Color(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, opacity: 0.7), cornerRadius: 8.0)
                    }
                    Picker(selection: $index, label: Text("Email types")) {
                        ForEach(0 ..< emailOptions.count) {
                            Text(self.emailOptions[$0])
                        }
                    }
                }
                .padding(.horizontal, 16)

                Section(header: Text("Emails")) {
                    Slider(value: $volumeSliderValue, in: 0...100, step: 1)
                    .padding()
                    .accentColor(Color.blue)
                    .border(Color.blue, width: 3)
                }
                .padding(.horizontal, 16)
            }
            .navigationBarTitle("Settings")
        }
    }
}

In the above code, a state variable called volumeSliderValue is defined, which stores the current value of the slider. The Slider component is created by passing the volumeSliderValue along with a range of possible values across the Slider.

You can also add the Slider‘s increment value by defining the step value in the parameter. You can additionally change the color of the slider and the border around it using the modifiers, accentColor() and border(), respectively.

Conclusion

This article showcases the use of SwiftUI and how you can create a form using SwiftUI. While this article shows the basics of the concept, there’s a lot more that SwiftUI offers.

Check out the further resources below, such as the Apple’s documentation and the WWDC 2019 sessions given about this framework:

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

.
Sneh Pandya Exploring the horizon with a knack for product management. Co-host of the NinjaTalks podcast and community organizer at Google Developers Group. Explorer, adventurer, traveler.

Leave a Reply