コードを日本語へ! Swift UITextField, UITextViewがキーボードで隠れるのを防ぐ(UIScrollViewを使わずに)

参考にさせていただきました。

【Swift】UITextField, UITextViewがキーボードで隠れるのを防ぐ(UIScrollViewを使わずに) - Qiita

//UITextViewDelegateを実装
class HogeHogeController: UIViewController,UITextViewDelegate {

    

    //このテキストビューを動かします
    @IBOutlet weak var content: UITextView!{
        didSet{
            content.delegate = self
        }
    }
    
    @IBAction func btn_decide(_ sender: Any) {
    
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }

//テキストビューの入力が始まったときに呼ばれるメソッド。
// 一番初めのクラス定義でUITextViewDelegateを実装しているので自然と呼ばれます。
    func textViewShouldBeginEditing(_ textView: UITextView)-> Bool{
        
        content.resignFirstResponder()
        return true
    }

    //監視開始 viewWillAppearで呼んでおくと、何度でも呼び出してくれます。
    override func viewWillAppear(_ animated: Bool) {
        configureObserver()
    }

   //監視解除 画面が遷移または消えるときに呼ばれます。
    override func viewWillDisappear(_ animated: Bool) {
        removeObserver()
    }
    
//値監視の関数 下記に説明します。説明1
    func configureObserver(){
        //
        let notification = NotificationCenter.default

//ここでどんな関数を呼び出すかを決めます。
        notification.addObserver(self, selector:
//keyboardWillShow(自分で作った関数)が呼ばれます。
            #selector(keyboardWillShow(notification:)),
//これはアップルの指定の属性
                name: UIResponder.keyboardWillShowNotification,
                object: nil)
        
//キーボードが隠されるときにも値を監視します。なんでも、呼んだら、隠す。これがセットになる。
//飲んだら、乗るな。飲むなら乗るな これがセットになっている。
//ちなみに若いときには、 吐くなら飲むな というのもある。
//年齢が行くと、吐いてまででも飲まないといけない。フリーランスのつらいところ
        notification.addObserver(self,
                selector: #selector(keyboardWillHide(notification:)),
                name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    //監視を外す関数も作っておく。関数名は自分で自由につけるが、中身はほとんど同じになる。
    func removeObserver(){
        let notification = NotificationCenter.default
        notification.removeObserver(self)
    }
    
//セレクターで呼ばれた関数の前には @objc をつけてあげる。これが作法。
//詳しく書くとこのあたりのアップルの関数は、昔のObjective-Cで書かれているのである。
    @objc func keyboardWillShow(notification: Notification){
//キーボードの動く量を取ってきている。それぞれの機種でキーボードサイズが異なるため。
        let rect = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue

        //Viewが動く時間。これを決めておかないと、引数に指定されているので、従う。
        let duration: TimeInterval? = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double

//Viewを動かす。animateメソッド。
//ここに移動量を設定。クロージャーになっている。説明-2
        UIView.animate(withDuration: duration!, animations: { () in
            let transform = CGAffineTransform(translationX: 0, y: -(rect?.size.height)!)
            self.view.transform = transform
        
        })
    }
    
        
        
        // キーボードが消えたときに、画面を戻す
    @objc func keyboardWillHide(notification: Notification) {
            
        let duration: TimeInterval? = notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? Double
            UIView.animate(withDuration: duration!, animations: { () in
                
                self.view.transform = CGAffineTransform.identity
            })
        }
        
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        
    }
    
    @IBAction func backButton(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }
    
}

説明-1 NotificationCenter とは Notificationとの違い

設定したものに対し、値が変更したときに、教えてくれるもの addObserverメソッドでいくらでも追加できる。 そのときに呼ばれるメソッドをセレクターで設定し、その関数を呼ぶ。

Notification は NotificationCenterを介して渡される通知の事

郵便局がNotificationCenter で 手紙が Notification こう考えるとわかりやすい

説明-2 移動量がクロージャーになっているわけ。

//ここに移動量を設定。クロージャーになっている。説明-2
//{からがクロージャー
        UIView.animate(withDuration: duration!, animations: { () in
            let transform = CGAffineTransform(translationX: 0, y: -(rect?.size.height)!)
            self.view.transform = transform

まだ、キーボードが出ていないのに動いてはいけない。
クロージャーの中身は、飛ばされて、中身に値が整った時点で、呼び出される。
クロージャーの中で、移動量が設定されている。
よって移動量が決まるまでは呼ばれない。
キーボード入力に成るまで呼ばれないということ。