Steppers

Last updated on 29 Oct 2024.

Written by Jia Chen.

Steppers

Last updated on 29 Oct 2024.

Written by Jia Chen.

Steppers

Last updated on 29 Oct 2024.

Written by Jia Chen.

Scroll Down

On this page

On this page

Getting Started

Creating a Stepper

To create a Stepper, you will need to supply it with a Binding value and a Label—a companion label to describe the Stepper's content.

In the following example, a stepper can be used to increment and decrement an integer.

struct ContentView: View {
    
    @State private var counter = 0
    
    var body: some View {
        VStack {
            Text("\(counter)")
            Stepper("Counter", value: $counter)
        }
    }
}

Stepper with Text Labels

The easiest way to create a counter is by supplying it with a text label.

Note that, in this style, by default, the Stepper tries to take up as much space as possible. It will attempt to stretch to fill the entire width of the parent view. See Fitting & Filling views.

@State private var counter = 0
Stepper("Slices of Cake", value: $counter)

Stepper with Custom Labels

Like other controls, can also supply a Stepper with a custom label.

Stepper(value: $counter) {
    Image(systemName: "birthday.cake.fill")
}

Over a Range

You can define a custom Closed Range to limit the possible values of a Stepper.

For example, setting a range of 1...5 would mean that Swift will use any value from 1 to 5, inclusive.

With Text Labels

In the following example, the number of stars can be limited to a value between 1 and 5, inclusive.

@State private var numberOfStars = 1
Stepper("Stars: \(numberOfStars)", value: $counter, in: 1...5)

With Custom Labels

This will also work with a custom label.

In the following example, the number of stars is limited to 1 to 5, inclusive, and the label displays the number of stars using a ForEach within a Horizontal Stack. It uses a ternary operator to switch between a filled and unfilled star SF Symbol.

Stepper(value: $numberOfStars, in: 1...5) {
    HStack {
        ForEach(1..<6) { starIndex in
            Image(systemName: starIndex <= numberOfStars ? "star.fill" : "star")
        }
    }
}

With a Custom Step

By default, the step is often set to 1. However, you may want to customize the step of the stepper.

In the following example, a counter Double State variable is created with each step of the stepper, it is incremented/decremented by 0.1.

@State private var counter = 0.0
Stepper("Counter: \(counter)", value: $counter, step: 0.1)

You can also use this with a custom label.

In the following example, the opacity State variable can be used to customize the opacity of an Image label.

@State private var opacity = 0.0
Stepper(value: $opacity, step: 0.1) {
    Image(systemName: "square.fill")
        .opacity(opacity)
}

Custom Steps with Ranges

You can combine steps with custom ranges by preceding it with the in: parameter.

Stepper(value: $opacity, in: 0...1, step: 0.1) {
    Image(systemName: "square.fill")
        .opacity(opacity)
}

Going Further

Custom Stepper Behavior

You can create an entirely custom Stepper by supplying it with an onIncrement and onDecrement clause.

In the following example, the numberOfStars value will loop around when it becomes less than 1 or greater than 5.

@State private var numberOfStars = 1
Stepper("Stars: \(numberOfStars)") {
    numberOfStars += 1
    
    if numberOfStars > 5 {
        numberOfStars = 1
    }
} onDecrement: {
    numberOfStars -= 1
    
    if numberOfStars < 1 {
        numberOfStars = 5
    }
}

The same can be done with custom labels. Take note of the trailing closure syntax when supplying the 3 closures for the Label, onIncrement, and onDecrement.

Stepper {
    HStack {
        ForEach(1..<6) { starIndex in
            Image(systemName: starIndex <= numberOfStars ? "star.fill" : "star")
        }
    }
} onIncrement: {
    numberOfStars += 1
    
    if numberOfStars > 5 {
        numberOfStars = 1
    }
} onDecrement: {
    numberOfStars -= 1
    
    if numberOfStars < 1 {
        numberOfStars = 5
    }
}

Listen when Editing Changes

The On Editing Changed closure allows you to listen for changes when editing changes.

The code gets executed when

  1. The user taps down on the stepper

  2. The user releases from the stepper

On iOS and iPadOS, users can hold down on the increment or decrement button to further increment or decrement the value. In those cases, the On Editing Changed closure gets called when the user starts holding down and again when they release.

Stepper("Number of Cookies", value: $counter) { isEditing in
    if isEditing {
        print("Stepper is currently held down")
    } else {
        print("Stepper is released")
    }
}

This will also work with custom labels by appending the onEditingChanged: parameter.

Stepper(value: $counter) {
    Image(systemName: "circle.hexagongrid.circle.fill")
} onEditingChanged: { isEditing in
    if isEditing {
        print("Stepper is currently held down")
    } else {
        print("Stepper is released")
    }
}

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.

© 2024 Tinkertanker Pte Ltd / Swift Accelerator. All rights reserved.