UITextFieldがスクリーンの下に配置された場合にKeyBoardで隠れてしまうことがあります。そのような場合はUIScrollViewを使って移動させれば解決ですね。
Xcode 11.3.1
UITextFieldがKeyboardで隠れる
Androidであれば自動的にやってくれるのにと思うこともありますが、まあそれぞれコンセプトやらで違いがあるのは当然なのでしょう。逆にお互いに似通ったUIなどにすると「え〜っ」となりますので、勝手なもんです。
UIScrollView上にUITestFieldを設定する
基本的なUIScrollViewの使い方はこちらでやりました。今回はStoryBoardを使ってみます。
UIScrollViewをスクリーンにいっぱいに配置します。(後でコードで指定するのですが)
その上にUIImageView, UILabel, UITextField をそれぞれ配置
UILabelは背景を半透明の白にしてフォントを大きくして決めうちで「元気してる?」と入れました。
次はコードですが、こちらの基本的な内容を踏まえて、UIScrollViewの表示窓はスクリーンサイズにし、UIScrollViewの大きさをスクリーンの縦方向を2倍にしました。これで縦方向のみのスクロールになります。
ViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import UIKit class ViewController: UIViewController, UITextFieldDelegate, UIScrollViewDelegate{ @IBOutlet var scrollView: UIScrollView! @IBOutlet var imageView: UIImageView! @IBOutlet var label: UILabel! @IBOutlet var textField: UITextField! // Screenの高さ var screenHeight:CGFloat! // Screenの幅 var screenWidth:CGFloat! override func viewDidLoad() { super.viewDidLoad() scrollView.delegate = self textField.delegate = self // 画面サイズ取得 let screenSize: CGRect = UIScreen.main.bounds screenWidth = screenSize.width screenHeight = screenSize.height // 表示窓のサイズと位置を設定 scrollView.frame.size = CGSize(width: screenWidth, height: screenHeight) // 表示する画像 let img:UIImage = UIImage(named:"sample_img")! // UIImageView 初期化 imageView = UIImageView(image: img) // UIScrollViewに追加 scrollView.addSubview(imageView) scrollView.addSubview(label) scrollView.addSubview(textField) // UIScrollViewの大きさをスクリーンの縦方向を2倍にする scrollView.contentSize = CGSize(width: screenWidth, height: screenHeight*2) // スクロールの跳ね返り無し scrollView.bounces = false // ビューに追加 self.view.addSubview(scrollView) } // 改行でキーボードを隠す func textFieldShouldReturn(_ textField: UITextField) -> Bool { self.view.endEditing(true) return true } } |
これでStoryBoardの紐付けをそれぞれして起動してみます。
キーボードで隠れたので自分でスクロールさせて入力するところまでできました。
これを自動でやればいいのです、はい。
UIScrollViewを自動で移動させる
キーボードはUITextFieldを編集し始めると出現しますが、このタイミングで
UIRespomder.keyboardWillShowというNotificationが出ている訳です。
その情報をキャッチした後に、キーボードの上部とUITextFieldの底を調べて重なりを計算、重なっていた場合はUIScrollViewを移動させるというシナリオです。
viewWillAppearでNotificationCenterにkeyboardWillShowが現れるのをオブザーブさせます。
同様にKeyboardが隠れるケースkeyboardWillHideも監視させる。
viewWillDisappearではこれらを解放する処理も入れます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)) , name: UIResponder.keyboardDidHideNotification, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: self.view.window) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidHideNotification, object: self.view.window) } |
上のSelectorで指定したfunctionを記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@objc func keyboardWillShow(_ notification: Notification) { let info = notification.userInfo! let keyboardFrame = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue // bottom of textField let bottomTextField = textField.frame.origin.y + textField.frame.height // top of keyboard let topKeyboard = screenHeight - keyboardFrame.size.height // 重なり let distance = bottomTextField - topKeyboard if distance >= 0 { // scrollViewのコンテツを上へオフセット + 50.0(追加のオフセット) scrollView.contentOffset.y = distance + 50.0 } } @objc func keyboardWillHide(_ notification: Notification) { scrollView.contentOffset.y = 0 } |
50.0のオフセットを入れましたが状況に応じて変えてください
まとめのコード
以下まとめたものです。
ViewController.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
class ViewController: UIViewController, UITextFieldDelegate, UIScrollViewDelegate{ @IBOutlet var scrollView: UIScrollView! @IBOutlet var imageView: UIImageView! @IBOutlet var label: UILabel! @IBOutlet var textField: UITextField! // Screenの高さ var screenHeight:CGFloat! // Screenの幅 var screenWidth:CGFloat! override func viewDidLoad() { super.viewDidLoad() scrollView.delegate = self textField.delegate = self // 画面サイズ取得 let screenSize: CGRect = UIScreen.main.bounds screenWidth = screenSize.width screenHeight = screenSize.height // 表示窓のサイズと位置を設定 scrollView.frame.size = CGSize(width: screenWidth, height: screenHeight) // 表示する画像 let img:UIImage = UIImage(named:"sample_img")! // UIImageView 初期化 imageView = UIImageView(image: img) // UIScrollViewに追加 scrollView.addSubview(imageView) scrollView.addSubview(label) scrollView.addSubview(textField) // UIScrollViewの大きさを画像サイズに設定 scrollView.contentSize = CGSize(width: screenWidth, height: screenHeight*2) // スクロールの跳ね返り無し scrollView.bounces = false // ビューに追加 self.view.addSubview(scrollView) } // 改行でキーボードを隠す func textFieldShouldReturn(_ textField: UITextField) -> Bool { self.view.endEditing(true) return true } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)) , name: UIResponder.keyboardDidHideNotification, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: self.view.window) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidHideNotification, object: self.view.window) } @objc func keyboardWillShow(_ notification: Notification) { let info = notification.userInfo! let keyboardFrame = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue // bottom of textField let bottomTextField = textField.frame.origin.y + textField.frame.height // top of keyboard let topKeyboard = screenHeight - keyboardFrame.size.height // 重なり let distance = bottomTextField - topKeyboard if distance >= 0 { // scrollViewのコンテツを上へオフセット + 50.0(追加のオフセット) scrollView.contentOffset.y = distance + 50.0 } } @objc func keyboardWillHide(_ notification: Notification) { scrollView.contentOffset.y = 0 } } |
スクロールできましたでしょうか
References:
How to make a UITextField move up when keyboard is present?
大きい画像を UIScrollView でスクロールする
TextField のキーボードを閉じる方法を3つ