gpt4 book ai didi

ios - 如何创建只接受数字和一个点的 SwiftUI TextField?

转载 作者:行者123 更新时间:2023-12-04 14:02:04 26 4
gpt4 key购买 nike

如何创建一个只允许用户输入数字和一个点的 swiftui 文本字段?
换句话说,它在用户输入时逐位检查,如果输入是数字或点,并且文本字段没有另一个点,则该数字被接受,否则数字条目将被忽略。
使用步进器不是一种选择。

最佳答案

SwiftUI 不允许您为 TextField 指定一组允许的字符。实际上,这与 UI 本身无关,而是与您如何管理背后的模型有关。在这种情况下,模型是 TextField 后面的文本。所以,你需要改变你的 View 模型。

如果您在 $ 属性上使用 @Published 符号,您可以访问 Publisher 属性本身后面的 @Published。然后您可以将您自己的订阅者附加到发布者并执行您想要的任何检查。在这种情况下,我使用 sink 函数将基于闭包的订阅者附加到发布者:

/// Attaches a subscriber with closure-based behavior.
///
/// This method creates the subscriber and immediately requests an unlimited number of values, prior to returning the subscriber.
/// - parameter receiveValue: The closure to execute on receipt of a value.
/// - Returns: A cancellable instance; used when you end assignment of the received value. Deallocation of the result will tear down the subscription stream.
public func sink(receiveValue: @escaping ((Self.Output) -> Void)) -> AnyCancellable

实现:
import SwiftUI
import Combine

class ViewModel: ObservableObject {
@Published var text = ""
private var subCancellable: AnyCancellable!
private var validCharSet = CharacterSet(charactersIn: "1234567890.")

init() {
subCancellable = $text.sink { val in
//check if the new string contains any invalid characters
if val.rangeOfCharacter(from: self.validCharSet.inverted) != nil {
//clean the string (do this on the main thread to avoid overlapping with the current ContentView update cycle)
DispatchQueue.main.async {
self.text = String(self.text.unicodeScalars.filter {
self.validCharSet.contains($0)
})
}
}
}
}

deinit {
subCancellable.cancel()
}
}

struct ContentView: View {
@ObservedObject var viewModel = ViewModel()

var body: some View {
TextField("Type something...", text: $viewModel.text)
}
}

重要的是要注意:
  • $text($ 属性上的 @Published 符号)为我们提供了一个 Published<String>.Publisher 类型的对象,即发布者
  • $viewModel.text($ 上的 @ObservableObject 符号)给了我们一个 Binding<String>
  • 类型的对象

    那是完全不同的两件事。

    编辑 :如果您愿意,您甚至可以使用此行为创建自己的自定义 TextField。假设您要创建一个 DecimalTextField View :
    import SwiftUI
    import Combine

    struct DecimalTextField: View {
    private class DecimalTextFieldViewModel: ObservableObject {
    @Published var text = ""
    private var subCancellable: AnyCancellable!
    private var validCharSet = CharacterSet(charactersIn: "1234567890.")

    init() {
    subCancellable = $text.sink { val in
    //check if the new string contains any invalid characters
    if val.rangeOfCharacter(from: self.validCharSet.inverted) != nil {
    //clean the string (do this on the main thread to avoid overlapping with the current ContentView update cycle)
    DispatchQueue.main.async {
    self.text = String(self.text.unicodeScalars.filter {
    self.validCharSet.contains($0)
    })
    }
    }
    }
    }

    deinit {
    subCancellable.cancel()
    }
    }

    @ObservedObject private var viewModel = DecimalTextFieldViewModel()

    var body: some View {
    TextField("Type something...", text: $viewModel.text)
    }
    }

    struct ContentView: View {
    var body: some View {
    DecimalTextField()
    }
    }

    这样您就可以使用您的自定义文本字段,只需编写:
    DecimalTextField()

    您可以随时随地使用它。

    关于ios - 如何创建只接受数字和一个点的 SwiftUI TextField?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57822749/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com