0

のカウントMaxCountを制限するために propertyWrapperを書きました。ただし、view は trimmedを示していますが、 fullを示しています。StringTextFieldTextStringTextFieldString

below を介して期待される動作を実現できますViewModifierが、これは私には良い習慣ではないようです@propertyWrapper

TextField("Type here...", text: $text)
       .onChange(of: text) { newText in
            // Check if newText has more characters than maxCount, if so trim it.
            guard maxCount < newText.count else { text = newText; return }
            text = String(newText.prefix(maxCount))
        }

MaxCount.swift

@propertyWrapper struct MaxCount<T: RangeReplaceableCollection>: DynamicProperty {
    
    // MARK: Properties
    private var count: Int = 0
    @State private var value: T = .init()
    
    var wrappedValue: T {
        get { value }
        nonmutating set {
            value = limitValue(newValue, count: count)
        }
    }
    
    var projectedValue: Binding<T> {
        Binding(
            get: { value },
            set: { wrappedValue = $0 }
        )
    }

    // MARK: Initilizations
    init(wrappedValue: T, _ count: Int) {
        self.count = count
        self._value = State(wrappedValue: limitValue(wrappedValue, count: count))
    }
    
    // MARK: Functions
    private func limitValue(_ value: T, count: Int) -> T {
        guard value.count > count else { return value }
        let lastIndex = value.index(value.startIndex, offsetBy: count - 1)
        let firstIndex = value.startIndex
        return T(value[firstIndex...lastIndex])
    }
    
}

ContentView.swift

struct ContentView: View {

    @MaxCount(5) private var text = "This is a test text"
    
    var body: some View {
        VStack {
            Text(text)
            TextField("Type here...", text: $text)
        }
    }
}
4

1 に答える 1