NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

TextField with initial empty value for a number?

Forums > SwiftUI

I'm trying to create a TextField for a number that has an initial value of 0 but I do not want the text field to show any value unless it is higher than 0.

struct MyClass: View {
  @State private var quantity = 0

  private let quantityFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = Locale.current
        formatter.numberStyle = .decimal
        formatter.minimumFractionDigits = 3
        formatter.maximumFractionDigits = 3
        return formatter
    }()

    var body: some View {
      TextField("", value: $quantity, formatter: quantityFormatter)
                                .keyboardType(.decimalPad)
    }
}

This technically works but then the user has to delete the '0' value from the field to enter a different value.

I tried using an optional value instead but it seems like NumberFormatter doesn't work with optional values.

Finally, I tried using an empty string instead but of course that won't work with NumberFormatter either.

Is this a SwiftUI limitation or am I doing something wrong?

Thanks!

   

Minus 100 points to Hufflepuff for using the name MyClass for a Struct!

In this article Formatting a Textfield for Numbers @twostraws notes it's a bit limited in what it can do.

Additionally, I see you define quantity as an Integer. ( quantity = 0 )
Yet, you format it for 3 decimal places.

A user might enter 4.32, but when they hit return, the value will be 4. Just 4.

Change your body to this to validate:

var body: some View {
        VStack {
            Text( "quantity: \(quantity)")
            TextField("", value: $quantity, formatter: quantityFormatter)
                .keyboardType(.decimalPad)
                .textFieldStyle(.roundedBorder)
                .padding()
        }
    }

   

Have you tried adding this property to your NumberFormatter?

formatter.zeroSymbol = ""

2      

Luc asks:

Is this a SwiftUI limitation or am I doing something wrong?

Whenever I ask this question, the answer almost every time, is Yes!

Then I ask myself, "Self? Am I the first programmer on the planet who has asked this question."

And I know I'm not clever enough to be the first. Someone, somewhere has already asked and solved this question. So my next question is usually, "What would @twostraws do in this situation?" And he's answered this plenty of times! He looks in the documentation.

So, no this isn't a SwiftUI limitation. But where you erred was in not reading the rest of the documentaton.

You added .numberStyle, .minimumFractionDigits, and .maximumFractionDigits to your number formatter. (Frankly, not sure why you added those three, because your variable is an Integer!)

But a bit further down in the documenation, you'll find a section named "Configuring Numeric Symbols". There you'll scroll down and finally find:

var zeroSymbol: String?
The string used to represent a zero value.

If you don't want your users to see a 0, then ask NumberFormatter to substitute an empty string!

Paste this code into Playgrounds.

// Fun with NumberFormatter
// For: @lvandal
// By:  Obelix 2022.02.03
// Paste into Playgrounds

import SwiftUI
import PlaygroundSupport

struct FunWithNumberFormat: View {
    @State private var quantity = -500  // change this number a few times

    // Computed variable for testing
    var formattedLucNumber : String {
        Formatter.lucNumberFormat.string(from: NSNumber(value: quantity))!
    }

    var body: some View {
        VStack {
            Text("Fun with NumberFormatter").font(.body)
            TextField("Quantity", value: $quantity, formatter: Formatter.lucNumberFormat)
                .textFieldStyle(.roundedBorder)
                .frame(width: 200).padding()
            Text( "raw quantity: \(quantity)").padding(.bottom)
            Text( "formatted: \(formattedLucNumber)")
        }
    }
}

// This is a reusable number formatter
extension Formatter {
    static let lucNumberFormat: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .none
        formatter.minusSign   = "👺 "  // Just for fun!
        formatter.zeroSymbol  = ""     // Show empty string instead of zero
        return formatter
    }()
}
// Click to play in Playgrounds.
PlaygroundPage.current.setLiveView( FunWithNumberFormat().frame(width: 400, height: 300) )

   

Have you tried adding this property to your NumberFormatter?

Success! Thanks for the suggestion! :)

   

Sometimes I don't know why I bother......

   

Nice. I can definitely utilize this. Thanks for the posts.

   

Hi, first of all, thanks for this solution. Has helped me understand (and fix) the issue a lot. Unfortunately, in my case one issue seems to remain, though: I need my users to be able to enter a "0", but with this line:

 formatter.zeroSymbol = "" 

they can't as the "0" immediately get's replaced by the placeholder text . Is there any workaround so that the user get's shown the placeholder String while no value is entered but can also enter a zero?

Many thanks in advance!

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

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.