I'm trying to limit the range of numbers entered into a TextField in my SwiftUI app, specifically between 8 and 64. I've implemented ParseableFormatStyle to handle this, and I've defined a custom logic in the format function. However, even though the format function seems to be working correctly, the changes aren't reflected in the TextField.
struct PasswordRangeStyle: ParseableFormatStyle {
/// Define the strategy used for parsing double values.
var parseStrategy: PasswordRangeStrategy = .init()
/// Define the range of double values to be formatted.
let range: ClosedRange<Double>
/// Format the double value according to the defined range.
///
/// - Parameter value: The double value to be formatted.
/// - Returns: The formatted string representation of the value within the specified range.
func format(_ value: Double) -> String {
print(#function, value)
if value > range.upperBound {
print(#function, value, range.upperBound, "upperBound")
return range.upperBound.cleanStringValue
}
if value < range.lowerBound {
print(#function, value, range.lowerBound, "lowerBound")
return range.lowerBound.cleanStringValue
}
return value.cleanStringValue
}
}
struct PasswordRangeStrategy: ParseStrategy {
/// Parse the string representation of a double value.
///
/// - Parameter value: The string representation of the double value.
/// - Returns: The parsed double value.
func parse(_ value: String) throws -> Double {
print(#function)
return Double(value) ?? 8
}
}
extension FormatStyle where Self == PasswordRangeStyle {
/// Convenience method to create a PasswordRangeStyle instance with the specified closed range
/// of double values.
///
/// - Parameter range: The closed range of double values.
/// - Returns: An instance of PasswordRangeStyle configured with the provided range.
static func ranged(_ range: ClosedRange<Double>) -> PasswordRangeStyle {
PasswordRangeStyle(range: range)
}
}
extension Double {
var cleanStringValue: String {
return String(format: "%.0f", self)
}
}
Usage:
struct ContentView: View {
@State var passwordLength: Double = 16
var body: some View {
VStack {
TextField(
"",
value: $passwordLength,
format: .ranged(8...64)
)
.frame(width: 48, height: 49)
.keyboardType(.numberPad)
.multilineTextAlignment(.center)
.font(.callout.weight(.regular))
.foregroundStyle(.black)
.textFieldStyle(PlainTextFieldStyle())
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray)
)
Spacer()
}
.padding()
}
}
How can I ensure that the TextField properly reflects the restricted number range set by ParseableFormatStyle?
