如何通过函数格式化 TextField 输入字符串?
How to format TextField input string by function?
我有一个用于电话输入的简单 TextField,每次更改时都想对其进行格式化。
我正在使用 PhoneNumberKit,它工作正常,但我不明白如何在 textField 中的值更改后调用格式化函数。
电话格式化功能。
import SwiftUI
import PhoneNumberKit
import Combine
func formatTelephone(telephone : String) -> String
{
do {
let phoneNumber = PartialFormatter().formatPartial(telephone)
print(phoneNumber)
return phoneNumber
}
catch {
print("Generic parser error")
}
}
它做这样的事情:
formatTelephone("79152140700") -> "7 (915) 214 08-00"
formatTelephone("791521") -> "7 (915) 21"
我有一个像这样的 TextField
TextField("915 214 07 00" , text: $telephoneManager.telephone)
每次输入一个数字后,整个文本字段标签需要通过函数格式化,并以更好的方式显示用户输入。
为了得到你想要的,你需要使用 Combine(这两个方法在视图模型中的实现由你决定,因为它们完全取决于你的需要):
import SwiftUI
import Combine
class ContentViewModel: ObservableObject {
@Published var phoneNumber = ""
private var toCancel: AnyCancellable!
init() {
toCancel = $phoneNumber
.filter { !self.isFormatValid([=10=]) }
.map { self.convert([=10=]) }
.receive(on: RunLoop.main)
.assign(to: \.phoneNumber, on: self)
}
private func isFormatValid(_ str: String) -> Bool {
//here you must check if _str_ is already in the right format
true //just to make this example compile, but clearly this must be replaced with your code
}
private func convert(_ str: String) -> String {
//convert your string to be in the right format
"string in the correct format" //just to make this example compile, but clearly this must be replaced with your code
}
deinit {
toCancel.cancel()
}
}
struct ContentView: View {
@ObservedObject var contentViewModel = ContentViewModel()
var body: some View {
TextField("Your phone number...", text: $contentViewModel.phoneNumber)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
步骤是(查看视图模型init):
phoneNumber
是 @Published
属性,因此您可以订阅的发布者 "it's backed"。那么,让我们订阅那个发布者吧。
- 您必须检查文本字段中的字符串是否已经采用正确的格式。这是最重要的:如果您错过了这一步,您将陷入无限循环。这是通过
.filter
运算符完成的。仅当 .filter
运算符 return 为真时才会向下转发事件(在本例中,如果字符串格式无效,则 return 为真)。
- 使用
.map
运算符,您可以更改字符串(格式错误)和 return 正确格式的字符串。
.receive
让您可以在您感兴趣的线程上转发事件。在本例中是主线程(因为您要更新文本字段)。
.assign
只是将新值分配给文本字段。
我有一个用于电话输入的简单 TextField,每次更改时都想对其进行格式化。
我正在使用 PhoneNumberKit,它工作正常,但我不明白如何在 textField 中的值更改后调用格式化函数。
电话格式化功能。
import SwiftUI
import PhoneNumberKit
import Combine
func formatTelephone(telephone : String) -> String
{
do {
let phoneNumber = PartialFormatter().formatPartial(telephone)
print(phoneNumber)
return phoneNumber
}
catch {
print("Generic parser error")
}
}
它做这样的事情:
formatTelephone("79152140700") -> "7 (915) 214 08-00"
formatTelephone("791521") -> "7 (915) 21"
我有一个像这样的 TextField
TextField("915 214 07 00" , text: $telephoneManager.telephone)
每次输入一个数字后,整个文本字段标签需要通过函数格式化,并以更好的方式显示用户输入。
为了得到你想要的,你需要使用 Combine(这两个方法在视图模型中的实现由你决定,因为它们完全取决于你的需要):
import SwiftUI
import Combine
class ContentViewModel: ObservableObject {
@Published var phoneNumber = ""
private var toCancel: AnyCancellable!
init() {
toCancel = $phoneNumber
.filter { !self.isFormatValid([=10=]) }
.map { self.convert([=10=]) }
.receive(on: RunLoop.main)
.assign(to: \.phoneNumber, on: self)
}
private func isFormatValid(_ str: String) -> Bool {
//here you must check if _str_ is already in the right format
true //just to make this example compile, but clearly this must be replaced with your code
}
private func convert(_ str: String) -> String {
//convert your string to be in the right format
"string in the correct format" //just to make this example compile, but clearly this must be replaced with your code
}
deinit {
toCancel.cancel()
}
}
struct ContentView: View {
@ObservedObject var contentViewModel = ContentViewModel()
var body: some View {
TextField("Your phone number...", text: $contentViewModel.phoneNumber)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
步骤是(查看视图模型init):
phoneNumber
是@Published
属性,因此您可以订阅的发布者 "it's backed"。那么,让我们订阅那个发布者吧。- 您必须检查文本字段中的字符串是否已经采用正确的格式。这是最重要的:如果您错过了这一步,您将陷入无限循环。这是通过
.filter
运算符完成的。仅当.filter
运算符 return 为真时才会向下转发事件(在本例中,如果字符串格式无效,则 return 为真)。 - 使用
.map
运算符,您可以更改字符串(格式错误)和 return 正确格式的字符串。 .receive
让您可以在您感兴趣的线程上转发事件。在本例中是主线程(因为您要更新文本字段)。.assign
只是将新值分配给文本字段。