Issue with Restricting Number Input Range in TextField using ParseableFormatStyle

31 Views Asked by At

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

This

How can I ensure that the TextField properly reflects the restricted number range set by ParseableFormatStyle?

0

There are 0 best solutions below