Swift4 テキストフィールドをキーボードに隠れないように変更

基本的な考え

スクロールビューをStoryBoardへ配置、IBOutlet 接続

まず入力されたテキストフィールドを取得(座標値)

Notificationにより、画面サイズ、キーボードのサイズを取得

テキストフィールドの位置が、キーボドサイズより小さければ、上方向へスクロール (contentOffset.y)

入力後はスクロールを0に戻す

以上の流れです。

では実装

テキストフィールドに入力開始時に呼ばれるデリゲートメソッド

ここにはメンバ変数に入力されたテキストフィールドを渡しているだけ。 どのテキストフィールドを呼ばれても、ここが呼ばれる。

引数がtextFieldで、編集に入ったテキストフィールドをメンバにわたす.

それをメンバ変数に持っておく。座標をメンバに持っておく

呼び出し時

  func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        //メンバ(座標保持)に現在入力されている textFieldを渡す。
        txtActiveField = textField
        return true
    }

上記で詰め込んだメンバ変数 ただのUITextField型で良い

  //メンバ
    var txtActiveField:UITextField?

ここで画面サイズを取得して、画面の一番上をget マージンを8pxにしてセットしている

//この関数名は適当で良い、下記のセレクターで渡している。
    @objc func handleKeyboardWillShowNotification(notification: Notification) {
        //userInfoにはキーボードの位置とサイズが、辞書型で入っている
        let userInfo = notification.userInfo!
        //userInfoからキーボードのフレームサイズを取得
        let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        //myBoudSize= 画面サイズ
        let myBoudSize:CGSize = UIScreen.main.bounds.size
        
        //origin.yはテキストフィールドの左上が取得できる 画面の座標系は左上が0.0 右下へ大きくなる
        let textLimit = txtActiveField!.frame.origin.y + txtActiveField!.frame.height + 8.0
        let kbdLmit = myBoudSize.height - keyboardScreenEndFrame.size.height
        if textLimit >= kbdLmit{
            scrollView.contentOffset.y = textLimit - kbdLmit
        }
        
    }

scrollViewは画面に配置しているもの

  @IBOutlet weak var scrollView: UIScrollView!

Notificationの構造体に移行されたようだ

またuserinfo はハッシュ

public struct Notification : ReferenceConvertible, Equatable, Hashable {

    public typealias ReferenceType = NSNotification

    /// Storage for values or objects related to this notification.
    public var userInfo: [AnyHashable : Any]?

UIKeyboardFrameEndUserInfoKeyはアップルのグローバル変数

スクリーン座標でキーボードの終了フレーム矩形を識別するCGRectを含むNSValueオブジェクトのキー。フレームの四角形は、デバイスの現在の向きを反映しています。

上記関数をセレクターで渡す。

画面呼び出すたびに呼ばれるviewWillAppearにセット

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
        
        let notification = NotificationCenter.default
        //addObserverにセットすることで監視してくれる
        notification.addObserver(self, selector: #selector(handleKeyboardWillShowNotification(notification:)) , name: .UIKeyboardWillShow, object: nil)
        
    }

addObserverの関数定義

func addObserver(_ observer: Any, 
        selector aSelector: Selector, 
            name aName: NSNotification.Name?, 
          object anObject: Any?)

observer :登録するオブジェクト

ここはこのクラスで宣言しているのでself

aSelector :通知を送付するメソッドを指定する。そのメソッドは一つだけ引数(オブジェクト)を保つ必要がある。

selectorの後に(関数名(引数))

aName :オブザーバーを登録する通知の名前。 .UIKeyboardWillShow

anObject:オブザーバが受信したい通知を持つオブジェクト。つまり、この送信者によって送信された通知のみがオブザーバに配信される

    //閉じるときの処理 アップルのデリゲートメソッド 自動的に呼ばれる
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        self.view.endEditing(true)
        return true
    }
    
    //閉じるときの処理 縦スクロールの値に0を入れる
    func handleKeyboardWillHideNotification(notification: Notification) {
        scrollView.contentOffset.y = 0
    }