SwiftUIのTextFieldに入力できる数値の最大値と最小値を設定する

個人で開発しているオープンソースMacアプリMizuameでTextFieldに数値の入力制限を設けたのですが、間抜けな実装をしてしまったのでうまく動作せず、バグありのままAppStoreにリリースしてしまいました。macOS 13.xのときは動作していたはずなのですが、macOS 14.0で動作していませんでした。
その間抜けな実装は以下の通りです。

TextField("Value", value: $inputValue)
    .onChange(of: inputValue) { val in
            if val < minVal {
                    inputValue = minVal
            }

            if val > maxVal {
                    inputValue = maxVal
            }
    }

onChange()を使うと、入力や削除があるたびに最大値・最小値のチェックができます。一見問題なさそうですが、1文字を入力または削除した瞬間に最大値または最小値を超えてしまうと現在値が訂正されてしまうので、望む値に変更できません。

例えば、最小値minValに100、最大値maxValに500が設定されていて現在値inputValが200の場合、現在値を300に変更しようとして 2 を削除すると、その瞬間に現在値が「00」となり最小値minVal(=100)を下回るので、入力制限により現在値inputValueが100に設定されてしまいます。

実際の間抜けなコードはこちらです

https://github.com/3colorr/Mizuame/blob/v1.1.2/Mizuame/Settings/TabStickyNote.swift#L85github.com

つまるところ、どうすべきだったか?というと、NumberFormatterを使うべきでした。

private var valueFormatter = NumberFormatter()

init() {
    valueFormatter.minimum = 100
    valueFormatter.maximum = 500
}

TextField("Value", value: $inputValue, formatter: valueFormatter)

これでTextFieldに入力制限を掛けられます。

実際のソースコードはこちらです。

github.com

ブログ中で使ったソースコードは個人開発しているMac向けのメニューバーからアクセスするノートアプリMizuameのものです。MITライセンスのオープンソースですので、実際のソースコードはこちらから確認できます。

github.com

AppStoreにも公開しています。
広告は好きではないので付いてません。

Mizuame

Mizuame

  • Akira Nakamura
  • ユーティリティ
  • 無料
apps.apple.com