SwiftUI offers great functionalities for creating forms. There is a special container named Form, which identifies that a form should be displayed on the screen. All fields between the Form container will be marked up automatically.

New to SwiftUI? Read my blog post with an introduction to SwiftUI.

TextField

A TextField is a UI element where a user can fill in some text using the keyboard. When initializing a TextField element, two properties are required. The first property is the placeholder of the TextField. The second property is a property wrapper variable, containing the value of the TextField.

To create a property wrapper variable in SwiftUI, define a variable and add the text @State before. When referring to the property in the TextField, use a dollar sign.

Example of a TextField in SwiftUI:

struct PersonalDetailsFormView: View {
    @State private var name: String = ""
    
    var body: some View {
        Form {
          TextField("Your name", text: $name)
        }
    }
}

Each time the user fills in a letter on the keyboard, the property wrapper ‘name’ will be updated with the new value of the TextField. If you display the value of the property ‘name’ somewhere on the screen, for example in a Text object, the rendering of the value is visible immediately.

It is easy to change the keyboard type for a TextField, for example, if you want to ask the age of the person. This can be done using the function .keyboardType(UIKeyboardType).

Example:

TextField("Your age", text: $age).keyboardType(.numberPad)

Picker

Using a picker, a user can select an option from a pre-defined list of options. Only one option can be selected. To create a picker, three properties are needed. First, you need to set the label of the picker, similar to the TextField.

The second property is a property wrapper which contains the index path of the selected state. Most of the time the default of this can be 0, but if you want to have a custom pre-selected index, you can edit this number.

Finally, the content of the picker needs to be set in the content block. The content can be defined using the Text elements.

Example of a Picker in SwiftUI:

struct PersonalDetailsFormView: View {
    @State private var selectedGenderIndex: Int = 0
    
    private var genderOptions = ["🙍‍♂️ Male", "🙍‍♀️ Female", "🤖 Other"]
    
    var body: some View {
        NavigationView {
            Form {
                Picker("Gender", selection: $selectedGenderIndex) {
                    ForEach(0..<genderOptions.count) {
                        Text(self.genderOptions[$0])
                    }
                }
            }.navigationBarTitle("Personal information")
        }
    }
}

When using the default picker style, a NavigationView is needed. This is because when you want to select an option, a new screen must appear where the user can select the option (just like settings app on iOS). You can easily change the view of the picker, which can be done using the function .pickerStyle( PickerStyle).

Example of function .pickerStyle( PickerStyle):

Picker("Gender", selection: $selectedGenderIndex) {
  // render picker options
}.pickerStyle(SegmentedPickerStyle())

In the example above, the picker style is set to SegmentedPickerStyle. There are multiple different styles, but for the example of selecting the gender there are not many options to select, so the SegmentedPickerStyle is perfect in that case.

For iOS, there are three picker styles available.

DatePicker

A DatePicker is a user-friendly way to enter a date. The Picker is similar to the normal Picker, but the behavior of the picker is a bit different. When the user clicks on the picker, the picker opens animated on the same screen and the user is able to select a date. After selecting a date, the picker will close animated.

Note that the property wrapper needs to be a Date object because you want to store a date. In the example below I set the current date as default.

Example of a DatePicker in SwiftUI:

struct PersonalDetailsFormView: View {
    @State private var birthday = Date()
    
    var body: some View {
        Form {
            DatePicker(selection: $birthday, in: ...Date(), displayedComponents: .date) {
                Text("Birthday")
            }
        }
    }
}

Toggle

The Toggle is a checkbox for mobile, which is basically a boolean. It can be on (which is true) or off (which is false). Implementing a Toggle is not much different then other form fields, where a label and property wrapper are needed.

Example of a Toggle in SwiftUI:

struct PersonalDetailsFormView: View {
    @State private var acceptedTerms: Bool = false
    
    var body: some View {
        Form {
            Toggle("I agree to the terms & conditions", isOn: $acceptedTerms)
        }
    }
}

Section

Sometimes you want to put some fields together in a section, so the user gets a clear overview of the fields that are related to each other. This can be done using the Section container.

All elements that are listed between the section container, are below each other. If an element is inside another section, some space is set between those sections.

A section only contains a header label, which will be displayed in a small font above the form elements.

struct PersonalDetailsFormView: View {
    @State private var name: String = ""
    @State private var age: String = ""
    
    var body: some View {
        Form {
            Section(header: Text("Personal")) {
                TextField("Your name", text: $name)
                TextField("Your age", text: $age).keyboardType(.numberPad)
            }
        }
    }
}

SwiftUIFormHelper

Developing forms with SwiftUI works great, but not everything works ‘out of the box’. When editing a value in a TextField on a real device, the keyboard won’t appear with an offset and is also not automatically dismissed after pressing somewhere on the screen.

To make your form work smooth on real devices, I created the library SwiftUIFormHelper, which contains helper functions for hiding the keyboard and adding offset to the form when the keyboard appears.

SwiftUIFormHelper can be found on GitHub.

var body: some View {
   NavigationView {
      Form {
         TextField("Name", text: $name)
           .hideKeyboardOnTap()
      }
      .enableKeyboardOffset()
   }
}

Conclusion

SwiftUI offers a great way to build forms easy and fast. All fields that are needed to build a mobile form are available. Fields can be sorted by category using a section, so the user gets a clear overview of the form fields that are related to each other.

I made an example project, which can be found on GitHub. The example project contains all the form elements I described in this article.

🚀 Like this article? Follow me on Twitter for more SwiftUI related blogs!

Share and Enjoy !

0Shares
Categories:SwiftUI