Working with Picker in SwiftUI

Posted in SwiftUI

Updated on October 16th, 2021

⏱ Reading Time: 6 mins

I think we all agree that the greatest advantage of SwiftUI is the ability it offers to implement specific controls with just a couple of lines; that’s the exact opposite of UIKit, where even the simplest control needs several lines of code in order to properly initialize and configure it. So, just from that, it makes perfect sense why SwiftUI has gained so many fans since day one, and keeps doing so.

Even though SwiftUI is not perfect yet and there are many developers preferring UIKit over SwiftUI -and for good reasons-, we just can’t overlook that there are several natively provided controls (views according to SwiftUI’s terminology) which we can integrate in a SwiftUI view like a breeze. I’ve written about many of them in previous tutorials, and today I’m focusing on another one; the Picker view.

The Picker view is the number one candidate to use when it comes to give users a range of options to choose from. In SwiftUI, a picker can get various appearances pretty fast and painlessly; that’s quite helpful when different kind of pickers should appear in different places. Pickers can present any values we want to display as options to users. Configuring a picker does not require much time or effort; and in this post, you’re going to read everything you need in order to start using SwiftUI pickers right away.

Note: In a previous tutorial I had written about the color picker in SwiftUI. That’s another kind of picker specific to picking colors, and if you want, you may read more here.

Displaying a Picker

In the following snippet you can see the simplest way to initialize and present a Picker in a SwiftUI view:

The Picker view accepts three arguments:

  • A string value to display as the picker’s label in certain circumstances. More about that later.
  • The binding value of a source of truth (usually from a local property marked with the @State property wrapper).
  • The options that user will choose among, usually implemented as a series of Text views.

Focusing on the second point initially, $colorScheme demonstrated above is the binding value of the following @State property:

The initial value provided to such a property should indicate the option shown as selected by default. To make the match between that and the correct option among all those included in the picker’s closure, we use a tag value. Each option must have a different tag value, which we pass as arguments to the tag(_:) method right after each view. This can be anything, as long as the type of the values given to the tag(_:) method matches to the type of the value in the source of truth. In the above example I chose to be an integer value. The initial value 1 assigned to the colorScheme property matches to the tag value of the “Dark” option, and this will be the one automatically selected when the picker will appear.

Picker styles

There are a few different styles that we can apply to a Picker. These affect its appearance, and which one is the most appropriate to use depends on the needs of the app we are developing only.

If we don’t set a specific style, the default one is the menu style. In this case, the default option is displayed as a button. When tapped, a menu with the rest of options is popping up. For instance, the above few lines of code results to this:

Menu picker style displaying Dark and Light options.

Another style, familiar from the past, is the wheel style. This one presents all available options in a wheel that scrolls towards up or down. To apply that style to the picker, we must explicitly set it as shown right next:

Dark and light options in wheel picker

There is also the segmented style that we may apply to the picker. With it, a segmented control presents the picker’s options.

Note: You can read a tutorial about the segmented control in SwiftUI in this older post.

As happened previously, it’s necessary to provide the segmented style to the pickerStyle(_:) method in order to use it:

Light and dark in segmented picker

The wheel style is probably the most suitable for displaying a long list of options. With menu and segmented styles, users expect to find a small range of options to choose from.

Picker in Forms

The Picker view is particularly interesting when used in SwiftUI forms. If we don’t provide a specific style to use, then the picker has a totally different appearance that has nothing to do with the previously demonstrated ones. It displays a disclosure indicator next to the selected option, but in addition to that, the label’s text is also visible in the leading edge of the row that contains the picker.

On tap, a new view is showing up with all available options so users can choose from. This new view is created automatically, and it contains all the picker’s options in a list. A default navigation is put in motion in order to push and pop that secondary view, and let users go forth and back in order to change their selection.

However, there is a requirement in order for all that to work. We must contain the Form view in a Navigation view, otherwise the picker won’t be responding on our tap gestures.

The following code summarizes all that in a few lines. See that the top-level view is a Navigation view, which in turn contains a Form view. The form contains a Section view, and the section finally contains the picker:

Here’s the result of the above few lines:

Picker in form demonstrating the appearance of the additional system view to pick another option.

Listing multiple options

In all the previous parts I used the same picker example, which contained two specific options only. In general, doing so for a limited number of options is totally fine and acceptable. But it’s quite obvious that hardcoding long lists of options is not productive at all, and even more, it’s also impossible sometimes; what if the available options change dynamically?

In such cases there is a different approach to follow that leaves aside the use of tags that we’ve seen so far. We list all available options using a ForEach view.

Let’s see a simple demo. The following array contains all years as integer numbers from 2000 to 2021. The @State property holds the current value (year) that will be displayed as the default selection when the picker will appear:

The picker right next displays all years in a wheel. It makes use of the ForEach view, and the years array is given as argument:

The $0.formatted(.number.grouping(.never)) is the new way to work with formatters in iOS 15. Its job in this example is to remove the grouping separator from the displayed numbers, so years won’t appear like 2,021 or 2.021 (depending on the locale).

Years in wheel picker with 2021 being the last and selected year.

Pickers with custom types

Right above we used ForEach in order to display values of a basic data type (integer) in the picker. However, we can do the same with custom types as well. There is just one requirement, and that is that the custom type should conform to the Identifiable protocol.

Suppose that we are developing a game, and we have the following struct that represents a weapon and the damage it can cause. The id property is a requirement coming from the Identifiable protocol, and its purpose is to uniquely identify every Weapon object in a collection:

Now, let’s create an array with a few weapons, and a @State property with the default weapon of the player:

Giving the option to change weapon using a picker is quite similar to what demonstrated in the previous part. What actually changes is that instead of \.self, we specify the keypath to the property that uniquely identifies each displayed object; the id in this case:

Conclusion

Working with the Picker in SwiftUI is not a tricky task, as it makes it quite easy to present either just a handful or a long set of options. Changing its appearance by setting any of the available styles is equally easy, but in addition to that it’s also impressive how picker behaves when used in forms. I hope that the few examples presented in the above parts have provided you with all the needed information, so you can start integrating pickers in your SwiftUI projects with no hesitation. Thanks for reading, and stay tuned for more content to come.

Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.