You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 18:03:11