Skip to content

Latest commit

 

History

History
96 lines (69 loc) · 2.85 KB

Values.md

File metadata and controls

96 lines (69 loc) · 2.85 KB

Values - Displaying and edit custom types

For more convenient and type-safe displaying and editing of your custom types, Forms provides the ValueLabel and ValueField types.

ValueLabel

ValueLabel is like a UILabel but generic on a custom type. It exposes a value property and uses a formatter to convert a value to a String for display:

let label = ValueLabel(value: 4711, formatter: { "\($0) kg" })
label.value = 75

You can also provide an instance of a Formatter:

let euroFormatter = NumberFormatter()
euroFormatter.currencyCode = "EUR"
euroFormatter.numberStyle = .currency

let label = ValueLabel(value: 47.11, formatter: euroFormatter)

If you often use the same formatter for your custom type you can add a convenience initializer:

struct Euro {
  var amount: Double
}

extension ValueLabel where Value == Euro {
  convenience init(value: Value, style: TextStyle = .defaultLabel) {
    self.init(value: value, keyPath: \.amount, formatter: euroFormatter)
  }
}

This means you do not have to provide explicit formatter everywhere:

let label = ValueLabel(value: Euro(4711))
label.value = Euro(0)

Form already comes with similar initializers for integer and floating point types:

let label = ValueLabel(value: 47.11)
label.value += 100

ValueField

Similar to ValueLabel, ValueField is like a UITextField but generic on a custom type for editing custom values. However, to be able to edit a value it needs an instance of a TextEditor. TextEditor is a protocol and Form comes with two concrete implementations named ValueEditor and DecimalEditor.

ValueEditor comes with several convenience initializers:

/// Country code editor, e.g. +46
let editor = ValueEditor(isValidCharacter: isDigit, 
                         minCharacters: 1, 
                         maxCharacters: 3, 
                         prefix: "+")

let field = ValueField(value: "46", editor: editor)

When working with numeric values it is often better to use NumberEditor that uses a NumberFormatter to derive its behavior and formatting:

let editor = NumberEditor<Double>(formatter: euroFormatter)
let field = ValueField(value: 47.11, editor: editor)

For integer and floating point values you can pass the formatter directly:

let field = ValueField(value: 47.11, formatter: euroFormatter)

To avoid repetition, you typically add convenience initializers to ValueField for your custom types:

extension ValueField where Value == Euro {
  convenience init(value: Value, style: FieldStyle = .decimal) {
    let editor = NumberEditor<Double>(formatter: euroFormatter)
    self.init(value: value, keyPath: \.amount, editor: editor, style: style)
  }
}

This allows you to use your custom types directly with ValueFields:

let field = ValueField(value: Euro(0))