Goalist Developers Blog

読者です 読者をやめる 読者になる 読者になる

UITextFieldのキーボード操作で使えるTips

Storyboard Xcode iOS swift モバイルアプリ

こんにちは。
最近タイピング時に小指が痛い渡部です。

f:id:watabe1028:20170316174757j:plain

今日はアプリ開発時によく使うUITextFieldのキーボード操作に便利なTipsについて書きます。

結構面倒な実装だし、ググると色々なパターンがあって悩んでしまう人もいると思うので
個人的に一番簡単だと思う実装方法を紹介しようと思います。

多分最も使うであろう機能
1.ボタン押下でキーボードを閉じる
2.ボタン押下で次のUITextFieldに移動する
3.画面タップでキーボードを閉じる
4.入力欄にかぶらないように画面をひょいっと動かす
を順に書いて行きます。

1.ボタン押下でキーボードを閉じる

まずはSingle Applicationでプロジェクトを作成し、UITextFieldを設置します。

まずここでビルドするとUITextFieldをタップするだけでキーボードが表示されます。
(背景をlightgrayにしてます)

f:id:watabe1028:20170316173204p:plain

しかし、その後閉じることができません。

「return」ボタンを「Done」ボタンに変更し、閉じれるように変更します。

手順1

StoryboardでUITextFieldを選択し、「Return Key」を「Default」から「Done」に変更します。

f:id:watabe1028:20170316173232p:plain

手順2

UITextFieldをOutletでソースと紐づけます。
そのままDelegateの設定をし、必要なデリゲートメソッドを記述して行きます。

import UIKit

class ViewController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.delegate = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

デリゲートメソッドを追加

    // このメソッドを追加
    // Doneボタン押下でキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        textField.resignFirstResponder()
        return true
    }

これでキーボードを閉じる設定ができました。

2.ボタン押下で次のTextFieldに移動する

次は入力フォームのような複数のUITextFieldがある場合、
「Next」ボタンを押して次のUITextFieldに移動するように設定します。
今回はタグを使ってやってみます。

手順1

UITextFieldを一つ追加してOutletで繋ぎます。

最初のUITextFieldにはタグに「0(デフォルト)」を
追加したUITextFieldには「1」を設定します。

f:id:watabe1028:20170316173302p:plain f:id:watabe1028:20170316173324p:plain

手順2

最初のUITextFieldの「Return Key」を「Done」から「Next」に変更します。
追加したUITextFieldの「Return Key」を「Default」から「Done」に変更します。

手順3

先ほど追加したデリゲートメソッドの中身を変更します。
内容はボタンが押されたUITextFieldのタグによって次に進むか
キーボードを閉じるかを判断します。

    // このメソッドを修正
    // Doneボタン押下でキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        switch textField.tag {
        case 0:
            // タグが0ならsecondTextFieldにフォーカスを当てる
            secondTextField.becomeFirstResponder()
            break
        case 1:
            // タグが1ならキーボードを閉じる
            textField.resignFirstResponder()
            break
        default:
            break
        }
        return true
    }

コード的にはスマートではないですが、とってもシンプルですね。

これでフォーカスの移動とキーボードの閉じるが実装されました。

3.画面タップでキーボードを閉じる

実はUITextFieldのキーボードはキーボードをしまうインターフェースがありません。
なので大体のアプリでは画面の他の部分をタップするとキーボードが閉じるように設定されています。

手順1

タップジェスチャーを追加します。
Storyboardで「Tap Gesture Recognizer」をviewに追加します。

f:id:watabe1028:20170316173345p:plain

手順2

追加するとViewController上部に表示されるので
そこからソースと紐づけます。
今回はOutletではなくActionにします。

f:id:watabe1028:20170316173405p:plain

手順3

追加したメソッドに1行追加します。
たった1行です。

    // 画面タップ時に呼ばれる
    @IBAction func tapScreen(_ sender: Any) {
        self.view.endEditing(true)
    }

これで完了です。
実行すると画面タップでキーボードが閉じます。

4.入力欄にかぶらないように画面をひょいっと動かす

これはちょいと面倒です。
色々なやり方がありますが、個人的に最も簡単な方法は
入力時に画面自体を動かしてしまうことです。
ボタンを追加してキーボードに隠れてしまうように設置します。
仮にログインボタンとします。

f:id:watabe1028:20170316173427p:plain

手順1

NotificationCenterという通知をviewDidLoadに追加します。
キーボードを開く際に通知で画面を動かす処理を呼び出します。

通知の設定

        // キーボードを開く際に呼び出す通知
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        
        // キーボードを閉じる際に呼び出す通知
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
手順2

同様に閉じる処理を呼び出す処理も追加。

    // キーボード表示時
    func keyboardShow() {
        // キーボードを開く際に画面を上に50ずらす
        self.view.bounds = CGRectMake(0, 50, self.view.frame.size.width, self.view.frame.size.height)
    }
    
    // キーボード非表示時
    func keyboardHide() {
        // キーボードを閉じる際に画面を元に戻す
        self.view.bounds = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
    }

ついでにSwift3ではCGRectMakeはそのままでは使えないので
自分でラップさせます。
筋肉で解決です。

    // CGRectMakeをwrap
    func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
        return CGRect(x: x, y: y, width: width, height: height)
    }

以上の追加でキーボードの表示、非表示で画面がいい感じに動きます。

f:id:watabe1028:20170316173446p:plain

まとめ

いかがだったでしょうか?
以外に面倒なキーボード操作もこれくらいなら
コピペで10分で実装できます。
いちいち実装が面倒な時はこのブログをコピペで使って頂けたらと思います。