【Xcode/SwiftUI】数字以外の文字をTextFieldに入力出来ないようにする

通常のTextField & キーボード

電話番号や郵便番号など、数字以外の入力があり得ない場合は初めからアルファベットとかの入力を出来ないようにしておけば予期せぬバグも防げそうですよね。

なのでキーボードのタイプを数字オンリーにしてみましょう。

数字入力オンリーにするための設定

.keyboardType(.numberPad) // 数字のみ

.decimalPadというタイプもありますが今回は無視します、単純に数字以外にも点(.)が入力出来るようになるものです。

import SwiftUI

struct HomeView: View {
    @State private var number = ""

    var body: some View {
        ZStack {
            Color.orange.opacity(0.3)
                .ignoresSafeArea()
            VStack(spacing: 24) {
                Text("Number: \(number)")
                    .font(.system(size: 20, weight: .bold))
                TextField("Your Number", text: $number)
                    .textFieldStyle(.roundedBorder)
                    .keyboardType(.numberPad) // 追加
            }
            .padding()
        }
    }
}

ただこの実装に関して、見落としやすい落とし穴があります。それを今から見ていきましょう。

コピペには対応できない

キーボード内には数字しかないのでアルファベット等の入力が物理的に不可能となりますが、コピペからだと可能になってしまいます。

意外な落とし穴ですね、コピペからの入力も制御出来るようにしないといけませんね。

コピペの制御も出来るようにするには

一個のViewModelファイルを作って、そこで入力値の詳細な判定処理を加えてあげることで解決出来ます。

import SwiftUI

class TextFieldViewModel {
    @Published var number = "" {
        didSet {
            let numeralsOnlyInput = number.allSatisfy { $0.isNumber } // 数字以外は受け付けない
            if !numeralsOnlyInput { 
                self.number = oldValue
            }
        }
    }
}
import SwiftUI

struct HomeView: View {
    @StateObject private var viewModel = TextFieldViewModel()
    @State private var number = ""

    var body: some View {
        ZStack {
            Color.orange.opacity(0.3)
                .ignoresSafeArea()
            VStack(spacing: 24) {
                Text("Number: \(viewModel.number)")
                    .font(.system(size: 20, weight: .bold))
                TextField("Your Number", text: $viewModel.number)
                    .textFieldStyle(.roundedBorder)
                    .keyboardType(.numberPad)
            }
            .padding()
        }
    }
}