SwiftUI TextField仅允许输入时间格式的实现方案求助
SwiftUI TextField 时间格式输入限制方案
要实现仅允许输入HH:mm格式的时间(最多4位数字,自动插入冒号,禁止非数字字符),可以通过自定义Binding或者自定义Formatter两种方式实现,下面是具体方案:
方法一:自定义Binding(推荐,实时反馈更流畅)
通过自定义Binding的get和set方法,直接控制输入内容的过滤与格式化:
import SwiftUI struct ContentView: View { @State private var rawTime = "" // 存储原始数字,不带冒号 // 自定义时间绑定 private var timeBinding: Binding<String> { Binding( get: { // 显示时自动插入冒号 let digits = rawTime.filter { $0.isNumber } guard digits.count > 0 else { return "" } if digits.count > 2 { let hourPart = digits.prefix(2) let minutePart = digits.dropFirst(2).prefix(2) return "\(hourPart):\(minutePart)" } return digits }, set: { newValue in // 过滤非数字字符,最多保留4位数字 let filteredDigits = newValue.filter { $0.isNumber }.prefix(4) rawTime = String(filteredDigits) } ) } var body: some View { TextField("如 22:30", text: timeBinding) .textFieldStyle(.roundedBorder) .keyboardType(.numberPad) .padding() } }
效果说明:
- 用户输入数字时,会自动在第2位后插入冒号(比如输入
2230会显示22:30,输入22显示22,输入223显示22:3) - 自动过滤所有非数字字符(包括复制粘贴的内容)
- 最多允许输入4位数字,超过部分会被截断
方法二:自定义Formatter
如果偏好使用Formatter体系,可以自定义一个时间输入Formatter:
import SwiftUI class TimeInputFormatter: Formatter { override func string(for obj: Any?) -> String? { guard let rawDigits = obj as? String else { return nil } let digits = rawDigits.filter { $0.isNumber }.prefix(4) let str = String(digits) if str.count > 2 { return "\(str.prefix(2)):\(str.dropFirst(2))" } return str } override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool { // 提取数字并截断到4位,存储原始值 let filteredDigits = string.filter { $0.isNumber }.prefix(4) obj?.pointee = String(filteredDigits) as AnyObject return true } } struct ContentView: View { @State private var rawTime = "" private let timeFormatter = TimeInputFormatter() var body: some View { TextField("如 22:30", value: $rawTime, formatter: timeFormatter) .textFieldStyle(.roundedBorder) .keyboardType(.numberPad) .padding() } }
可选优化:时间合法性校验
如果需要确保输入的时间有效(比如小时≤23,分钟≤59),可以在自定义Binding的set方法里加入校验逻辑:
set: { newValue in let filteredDigits = newValue.filter { $0.isNumber }.prefix(4) let rawStr = String(filteredDigits) // 校验小时和分钟的合法性 if rawStr.count >= 2 { let hourStr = rawStr.prefix(2) if let hour = Int(hourStr), hour > 23 { // 小时超过23,自动修正为23 rawTime = "23" + rawStr.dropFirst(2).prefix(2) return } } if rawStr.count == 4 { let minuteStr = rawStr.suffix(2) if let minute = Int(minuteStr), minute > 59 { // 分钟超过59,自动修正为59 rawTime = rawStr.prefix(2) + "59" return } } rawTime = rawStr }
内容的提问来源于stack exchange,提问作者Damiano Miazzi
相关产品推荐
相关产品推荐

