技術ブログ

プログラミング、IT関連の記事中心

TextFieldに英数記号のキーボードのみを表示する方法【Swift】

■はじめに

ここでは、以下の要望への対応方法を記載します。

  • TextFieldにフォーカスを当てた時のキーボードを、英数記号のみにして欲しい
  • ユーザーの設定関係なく、英数記号のキーボードにして欲しい。
  • キーボードの切り替えを許さないで欲しい
  • パスワード入力以外のTextFieldに使いたい(●は出さないで欲しい)

iOSの事を知らない人はこんな無茶苦茶な要望してくる人もいるかもしれません。

(実際にされた人を知っていますw)

上記は、iOSのデフォルト機能だけでは実現することができません。

「●」は出さないで欲しい。が一番の原因ですね。。。

■手順

最終的にこんな感じのキーボードが表示されます。

(パスワード用のキーボードだとスクショに映らないので、写真で取りました。。。見辛くてすみません。。。)

まずは、結論から。

CustomTextField.swiftを作成して以下をコピペしてください。

import UIKit

class CustomTextField: UITextField, UITextFieldDelegate {
    // パスワード入力フィールド(画面上には表示しない)
    var passText = UITextField()
    
    /// 初期化処理
    /// - Parameter frame: frame description
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    /// 初期化処理
    /// - Parameter aDecoder: aDecoder description
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    /// 初期化処理で呼び出す共通処理
    func commonInit() {
        // 非表示のテキストフィールドをパスワード入力フィールドに設定
        passText.isSecureTextEntry = true
        
        // キーボードの上のiCloudから入力する「パスワード」の部分の非表示
        if #available(iOS 12.0, *) {
            passText.textContentType = .oneTimeCode
        }
        
        // TextFieldのデリゲートでフォーカス時、値入力時の制御を行う
        self.delegate = self
        passText.delegate = self
        
        // パスワード入力テキストフィールドを非表示状態でViewに追加
        passText.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        self.addSubview(passText)
    }
    
    
    /// フォーカス時処理
    /// - Parameter textField: textField description
    func textFieldDidBeginEditing(_ textField: UITextField) {
        // フォーカスが当たったあと、一瞬遅延させる(即時にフォーカス切り替えが動かないので)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
            // フォーカス制御はメインスレッドで
            DispatchQueue.main.async {
                // パスワード入力TextFIeldにフォーカスを当てる
                self.passText.becomeFirstResponder()
            }
        }
    }
    
    /// 値入力(削除)時処理
    /// - Parameters:
    ///   - textField: textField description
    ///   - range: range description
    ///   - string: string description
    /// - Returns: description
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // 値をTextFieldに反映
        self.text = textField.text
        // 一瞬遅延
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
            // メインスレッドで処理
            DispatchQueue.main.async {
                // パスワード入力TextFieldの値を表示されているTextFieldに設定
                self.text = self.passText.text
            }
        }
        return true
    }
}

使い方は以下のような感じで、使ってください。(普通のUITextFieldと同じです)

let text = CustomTextField()
text.frame = CGRect(x: 50, y: 160, width: 100, height: 30)
text.layer.borderColor = UIColor.blue.cgColor
text.layer.borderWidth = 1
self.view.addSubview(text)

この方法のポイントとしては、「passText」です。

これを画面に見えないように精製して、TextFieldにフォーカスされたタイミングで「passText」にフォーカスさせています。

で、「passText」に値が入力された際にTextFieldに反映させています。

結果、TextFieldに値が入力されているようにみえます。

他に方法があれば、是非ご連絡ください。