如何通过函数格式化 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):

  1. phoneNumber@Published 属性,因此您可以订阅的发布者 "it's backed"。那么,让我们订阅那个发布者吧。
  2. 您必须检查文本字段中的字符串是否已经采用正确的格式。这是最重要的:如果您错过了这一步,您将陷入无限循环。这是通过 .filter 运算符完成的。仅当 .filter 运算符 return 为真时才会向下转发事件(在本例中,如果字符串格式无效,则 return 为真)。
  3. 使用 .map 运算符,您可以更改字符串(格式错误)和 return 正确格式的字符串。
  4. .receive 让您可以在您感兴趣的线程上转发事件。在本例中是主线程(因为您要更新文本字段)。
  5. .assign 只是将新值分配给文本字段。