Swift实现塞尔维亚手机号实时格式化,消除粘贴显示延迟
SwiftUI实现手机号即时格式化消除粘贴延迟
问题背景
需要实现塞尔维亚手机号的实时格式化:输入+381 65 1234 123时自动转为0651234123。已编写normalizeSerbianPhoneNumber函数完成格式转换,但在TextField中粘贴号码时,会短暂显示原始内容再切换为格式化后的值,存在明显延迟,需要实现无延迟的即时格式化。
现有格式化函数
func normalizeSerbianPhoneNumber(_ mobileNumber: String) -> String { let allowedCharacterSet = CharacterSet(charactersIn: "+0123456789") let trimmedNumber = mobileNumber.trimmingCharacters(in: .whitespacesAndNewlines) var strippedNumber = trimmedNumber.trimmingCharacters(in: allowedCharacterSet.inverted) // 移除所有空格 strippedNumber = strippedNumber.replacingOccurrences(of: " ", with: "") // 移除前缀国家码或多余的0 if strippedNumber.hasPrefix("+381") { strippedNumber.removeFirst(4) } else if strippedNumber.hasPrefix("381") { strippedNumber.removeFirst(3) } else if strippedNumber.hasPrefix("0") { strippedNumber.removeFirst() } // 验证并返回格式化后号码 // 塞尔维亚手机号通常以6开头,长度为8或9位 if (strippedNumber.count == 8 || strippedNumber.count == 9) && strippedNumber.hasPrefix("6") { return strippedNumber } else { return "" // 替换原错误字符串,避免TextField显示无效文本 } }
问题根源
原代码使用.onChange(of: phoneNumber)监听值变化后再修改,这会导致TextField先更新为原始输入/粘贴值,再触发格式化修正,因此产生延迟。要解决这个问题,需要在值被绑定到TextField时就直接完成格式化,而非等待值变化后再调整。
解决方案:自定义Binding
通过自定义Binding,在set阶段直接处理输入值的格式化,确保TextField显示的始终是处理后的值,消除延迟:
struct PhoneNumber: View { var title: String let phoneNumber: Binding<String> @State private var showSheet: Bool = false var action: () -> () // 自定义格式化Binding private var formattedPhoneBinding: Binding<String> { Binding( get: { phoneNumber.wrappedValue }, set: { newValue in let formattedResult = normalizeSerbianPhoneNumber(newValue) // 避免重复赋值引发循环更新 if formattedResult != phoneNumber.wrappedValue { phoneNumber.wrappedValue = formattedResult } } ) } var body: some View { VStack(alignment:.leading){ Text(title) .font(.ubuntu(name: .ubuntuRegular, size: 12)) HStack{ CountrySelectButton(width: UIScreen.main.bounds.width - 290) { showSheet.toggle() } GrayTextField(placeholder: "000 000 0000", text: formattedPhoneBinding) .keyboardType(.phonePad) } }.sheet(isPresented: $showSheet) { SelectCountrySheet() .presentationDragIndicator(.hidden) .presentationDetents([.medium, .large]) } } }
额外优化建议
- 错误提示优化:不要在格式化函数中返回错误字符串,而是单独添加一个Text组件显示错误信息(比如当格式化结果为空时),避免TextField显示无关文本。
- 部分有效输入处理:如果用户输入未完成(比如仅输入了
65123),可以返回已输入的有效数字,而非直接返回空,提升输入流畅度。 - 长度限制:在自定义Binding的set方法中添加长度限制,防止用户输入过多无效字符。
内容的提问来源于stack exchange,提问作者Luka Šalipur
相关产品推荐
相关产品推荐

