UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Day 47: Habit Tracker changing activity count

Forums > 100 Days of SwiftUI

This seems to be a stupid question but I'm struggling to find an answer, here's part of my codes where user can update the count of any activity in the details view:


      Stepper("\(activity.count) \(activity.count <= 1 ? "time" : "times")", onIncrement: {
          newActivity.count += 1
          changeCount(for: activity, updatedActivity: newActivity)
      }, onDecrement: {
          newActivity.count -= 1
          changeCount(for: activity, updatedActivity: newActivity)
      })

My question is how can I prevent the stepper from going below 0? I want to specify a range but it does not allow me to add an "in: 0..." parameter to it.

It's not covered by the examples in the definition or have I missed it? Thanks for your help!

1      

Your Stepper seems overly complicated, but maybe I'm not understanding what you're trying to do. Here's a simple Stepper that stays between 0 and 10:

struct ContentView: View {
    @State private var count = 0.0

    var body: some View {
        Form {
            Stepper("Count: \(count.formatted())", value: $count, in: 0...10, step: 0.25)
        }
    }
}

2      

@vtabmow Thanks for your reply!

Actually I want to call the changeCount() function whenver user change the value of activity count using the stepper. This will change the value of newActivity.count while newActivity is a copy of the current activity struct instance, and will be used to replace it in the original activities array.

I think I just want to know if it's possible to specify the range like you do when closures like onIncrement / onDecrement are passed in, somehow like this:

Stepper(
  "<Text here>", 
  value: <$binding>, 
  in: <range>, 
  onIncrement: { 
   // Do something
      }, 
  onDecrement: {
   // Do something      
   })

If not then how should it be done?

1      

You could try

First need a property to track count

@State private var oldCount = 0

then do this (where count is your activity.count)

Stepper("\(count)", value: $count, in: 0...10)
      .onAppear {
          oldCount = count
      }
      .onChange(of: count) { newCount in
            if newCount > oldCount {
                print("Increased Count - changeCount()")
            } else {
                print("Decreased Count - changeCount()")
            }
            oldCount = newCount
        }
      }

1      

Or you can do

Stepper("\(count)") {
    if count <= 10 {
        count += 1
        print("Increased Count - changeCount()")
    } else {
        count = 10
    }
} onDecrement: {
    if count > 0 {
        count -= 1
        print("Decreased Count - changeCount()")
    } else {
        count = 0
    }
}

1      

Part of the problem is that it seems you may want to use a one-sided range, at least judging by this:

I want to specify a range but it does not allow me to add an "in: 0..." parameter to it.

0... is a PartialRangeFrom. The Stepper initializers that accept an in parameter only take a ClosedRange (e.g., 0...10).

You can simulate a PartialRangeFrom like so:

Stepper("\(count)") {
    count += 1
} onDecrement: {
    count = max(0, count - 1)
}

1      

Thanks you all for the advice, I get it now!

1      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.