WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

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!

   

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)
        }
    }
}

1      

@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?

   

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
        }
      }

   

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
    }
}

   

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)
}

   

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

   

Hacking with Swift is sponsored by Fernando Olivares

SPONSORED Fernando's book will guide you in fixing bugs in three real, open-source, downloadable apps from the App Store. Learn applied programming fundamentals by refactoring real code from published apps. Hacking with Swift readers get a $10 discount!

Read the book

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

Reply to this topic…

You need to create an account or log in to reply.

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.