Reputation: 6037
I want to use the Stepper view in manual (not binding) mode using onIncrement and onDecrement. There's a strange behavior when I try to implement lower and upper bounds, eg. having an age value not going bellow 1 or above 10.
If you try the bellow code, you can press "-" two times after it already has the value "1". It doesn't go bellow 1 as expected, but after the two additional presses the "-" button suddenly gets disabled. If you then press "+" nothing happens. Only after 2 additional presses to "+" the counter reacts as expected and goes to 2.
Is this a bug?
struct StepperTest: View {
@State private var age = 5
var body: some View {
VStack {
Stepper("Enter your age", onIncrement: {
if self.age < 10 {
self.age += 1
print("Adding to age")
}
}, onDecrement: {
guard self.age > 1 else { return }
self.age -= 1
print("Subtracting from age")
})
Text("Your age is \(age)")
}
}
}
Upvotes: 8
Views: 2312
Reputation: 11143
I was seeing similar behavior as described using iOS 14.5 in Xcode 12.5.1. I found this open radar which describes the bug: https://openradar.appspot.com/FB7669491
In my case I was passing functions in my view model directly as the onIncrement
and onDecrement
parameters when initializing the Stepper
:
Stepper("Label", onIncrement: viewModel.increment, onDecrement: viewModel.decrement)
Based on reading the radar, the current issue is caused by passing functions outside the view as the values for these parameters. Changing my code to this fixed the issue for me:
Stepper("Label", onIncrement: { viewModel.increment }, onDecrement: { viewModel.decrement })
Upvotes: 1
Reputation: 105
I was seeing the same thing. Definitely seems like a bug on Apples side to me. As one of the commenters mentioned, you can use the onEditingChanged parameter. This should give you all the functionality that you would need. As the bound variable changes with the Stepper inputs you are able to take an action. It looks like this:
Stepper(value: $age, in: 1...10, step: 1, onEditingChanged: { didChange in
// take some action or make a calculation
})
{
Text("Your age is \(age)")
}
Upvotes: 1
Reputation: 51
Checking and resetting the value after incrementing seems to work:
Stepper("Enter your age", onIncrement: {
self.age += 1
if self.age > 10 {self.age = 10}
}
}, onDecrement: {
self.age -= 1
if self.age < 1 {self.age = 1}
})
Upvotes: 2
Reputation: 258621
I think here is explanation:
///
onIncrement
will be initialized tonil
if attempting to increment
///value
will have no effect. Likewise,onDecrement
will be initialized
/// tonil
if attempting to decrementvalue
will have no effect.
If you try
Stepper("Enter your age", onIncrement: {
print("Adding to age")
}, onDecrement: {
print("Subtracting from age")
})
... you'll see that steppers got into the same state, as you described, so Apple tracks rebuild of Stepper view, if no rebuild was initiated by user action on Stepper (ie. no effect) it disable itself.
Another question is why it's not at once...
Upvotes: 1