Advanced SwiftUI Stepper

Apple’s built in stepper allows you to only have one step increment value, I’ve designed on that allows for two different increment values. Initial version supported 1 and 10 for the step values and is tied to an integer.

import SwiftUI

struct ContentView: View {
    @State var score: Int = 0
    var min: Int = 0
    var max: Int = 100
    var template: String = "Score: %@"
    
    var body: some View {
        
        Form {
            Text("Expanded Stepper Example")
            HStack {
                Text(String(format: template, score.formatted()))
                Spacer()
                Button("-10") {
                    score = score - 10
                }
                .disabled(score - 10 < min)
                .buttonStyle(BorderlessButtonStyle())
                .padding(.horizontal, 4)
                
                Button("-1") {
                    score = score - 1
                }
                .disabled(score - 1 < min)
                .buttonStyle(BorderlessButtonStyle())
                .padding(.horizontal, 4)
                
                Button("+1") {
                    score = score + 1
                }
                .disabled(score + 1 > max)
                .buttonStyle(BorderlessButtonStyle())
                .padding(.horizontal, 4)
                
                Button("+10") {
                    score = score + 10
                }
                .disabled(score + 10 > max)
                .buttonStyle(BorderlessButtonStyle())
                .padding(.horizontal, 4)
            }
        }
    }
}

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

This of course is the first revision, and it isn’t very reusable in the current state. So the next step was to make it more reusable.

import SwiftUI


struct AdvancedStepper: View {
    var value: Binding<Int>
    var min: Int
    var max: Int
    var template: String
    
    var body: some View {
        HStack {
            Text(String(format: template, value.wrappedValue.formatted()))
            Spacer()
            Button("-10") {
                value.wrappedValue = value.wrappedValue - 10
            }
            .disabled(value.wrappedValue - 10 < min)
            .buttonStyle(BorderlessButtonStyle())
            .padding(.horizontal, 4)
            
            Button("-1") {
                value.wrappedValue = value.wrappedValue - 1
            }
            .disabled(value.wrappedValue - 1 < min)
            .buttonStyle(BorderlessButtonStyle())
            .padding(.horizontal, 4)
            
            Button("+1") {
                value.wrappedValue = value.wrappedValue + 1
            }
            .disabled(value.wrappedValue + 1 > max)
            .buttonStyle(BorderlessButtonStyle())
            .padding(.horizontal, 4)
            
            Button("+10") {
                value.wrappedValue = value.wrappedValue + 10
            }
            .disabled(value.wrappedValue + 10 > max)
            .buttonStyle(BorderlessButtonStyle())
            .padding(.horizontal, 4)
        }
    }
}

struct ContentView: View {
    @State var score: Int = 0

    var body: some View {
        Form {
            Text("Expanded Stepper Example")
            AdvancedStepper(value: $score, min: 0, max: 10, template: "Score: %@")
        }
    }
}

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

I think I’m happy enough with this one for now. Of course I could take this further and make the step amounts customizable by the usage location.