Joe's Blog

iOS 開發筆記

UITextField 限制輸入小數

發佈於 2020-12-25
2026-06-13 更新

金融、電商類的 app 常常需要限制輸入金額,只允許輸入合法的小數——不能有多個小數點、小數點後只能兩位、開頭不能多餘的零。

UITextField 本身不提供這些限制,需要自己透過 delegate 的 shouldChangeCharactersIn 來攔截每一次輸入。


設定

1
2
textField.keyboardType = .decimalPad
textField.delegate = self

decimalPad 讓鍵盤只顯示數字和小數點,但這只是 UI 層面的限制,使用者仍然可以透過貼上功能輸入任意字元,所以 delegate 的驗證不能省。


shouldChangeCharactersIn 實作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard let text = textField.text else { return true }

    // 1. 刪除事件直接放行
    guard !string.isEmpty else { return true }

    // 2. 只允許數字和小數點
    guard "0123456789.".contains(string) else { return false }

    // 3. 總長度限制(最多 10 位)
    if text.count >= 10 { return false }

    // 4. 小數點後最多 2 位
    if let dotRange = text.range(of: ".") {
        let dotIndex = NSRange(dotRange, in: text).location
        if range.location - dotIndex > 2 { return false }
    }

    // 5. 首位是 0 時,下一個只能是小數點
    if text == "0", string != "." {
        textField.text = string
        return false
    }

    // 6a. 首位直接輸入小數點,自動補成 "0."
    if text.isEmpty, string == "." {
        textField.text = "0."
        return false
    }

    // 6b. 禁止重複輸入小數點
    if text.contains("."), string == "." { return false }

    return true
}

六種邊界情況

情況處理方式
刪除(string 為空)直接放行
貼上非法字元攔截,return false
超過 10 位攔截,return false
小數點後超過 2 位攔截,return false
首位輸入 0 再輸入數字替換成輸入的數字
首位輸入小數點自動補成 0.
重複輸入小數點攔截,return false

SwiftUI 版本另見:SwiftUI TextField 限制輸入小數


本文使用 Claude 共同完成