Elektronenhirn
Elektronenhirn

Reputation: 198

TextField: display unselectable suffix and hide value if 0

I am trying to build a TextField that shows a suffix, like a unit, which the user can't select, and the value of the TextField should be hidden if it meets certain criteria; in my case, if the value is 0, so that the placeholder is displayed.

So far, I was able to archive to hide 0 or display a suffix using a NumberFormatter. value 0.0 value 42.0

extension Formatter {
    static let optionaNotNegative: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        formatter.currencySymbol = "SUFFIX"
        formatter.zeroSymbol = ""
        return formatter
    }()
}

struct SuffixTextFieldView: View {
    @State private var value = 0.0 // 42
    var body: some View {
        TextField("Cost", value: $value, formatter: .optionaNotNegative)
            .keyboardType(.decimalPad)
    }
}

#Preview {
    SuffixTextFieldView()
}

However, I can select and delete the suffix while editing, which shouldn't be the case. Additionally, the NumberFormatter is only applied to the initial value and after submitting using the keyboard. Submitting is sometimes not possible, like when using .decimalPad.

Therefore, the suffix is not shown when the TextField was empty at the beginning or when it was deleted by the user. enter image description here Additionally, 0 doesn't get hidden when this wasn't the original value. value 0.0

I also had a look at TextFieldStyle, but it seems like it is not possible to access and style the displayed value itself.

How can I achieve the desired behavior somehow?

Upvotes: 0

Views: 133

Answers (1)

flanker
flanker

Reputation: 4200

A basic solution (without much thought for layout!) could look something like this:

extension Formatter {
   static let optionalNotNegative: NumberFormatter = {
      let formatter = NumberFormatter()
      formatter.zeroSymbol = ""
      return formatter
   }()
}


struct TextWithSuffixView: View {
   @Binding var value: Double
   var body: some View {
      HStack {
         TextField("Enter Cost", value: $value, formatter: .optionalNotNegative)
            .keyboardType(.numberPad)
            .multilineTextAlignment(.trailing)
            .frame(width: 100, alignment: .center)
         Text(value > 0 ? "SUFFIX" : "")
      }
   }
}

Note that the currency formatting and currency symbol have been removed from the formatter, and that it is using a Binding rather than a State variable to allow the value to be injected by and bound to a parent view.

You would need to think how you want to handle a when a user deletes all content of the text field. The formatter's .number(from: String) -> NSNumber? will return nil and the bound value won't be updated, so while the textfield will be empty, the value will retain its previous value.

Upvotes: 0

Related Questions