御機嫌よう、ガラパゴスのおとめです。
今日は、UITextViewを、オートレイアウトを使って、キーボードを除いた画面いっぱいのサイズにしてみようと思います。UIScrollViewに入れてキーボード表示時にスクロールさせるのではなく、使える広さは全部UITextViewにします。
この記事は、Swift 3.0とXcode 8.2.1を対象としています。
Viewの作成
適当にプロジェクトを作成して画面を作ります。よくある感じのUITableViewのある画面で追加ボタンを押すと入力画面を表示するイメージでViewを作成し、Text View
を適当にドロップしたら、Add New Constraints
で上下左右を0
に設定します。
キーボードの通知を受け取る
さて、UITextViewは画面いっぱいにしていますが、このままでは下部がキーボードに隠れてしまいます。そこで、キーボードが表示された時に大きさを調整する必要があります。
キーボードに関連する通知は、NotificationCenter
を通じて取得することができます。キーボード関連の通知は以下のようになっています。
通知 | 呼ばれるタイミング |
---|---|
.UIKeyboardWillShow | キーボードが表示される時 |
.UIKeyboardDidShow | キーボードが表示された後 |
.UIKeyboardWillChangeFrame | キーボードがViewの位置やサイズを変更する時 |
.UIKeyboardDidChangeFrame | キーボードがViewの位置やサイズを変更した後 |
.UIKeyboardWillHide | キーボードが非表示になる時 |
.UIKeyboardDidHide | キーボードが非表示になった後 |
通知を処理するには、NotificationCenter.addObserver(...)
で、通知とそれを受け取る関数を指定します。ここではViewが表示される時に呼び出します。
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let notificationCenter = NotificationCenter.default notificationCenter.addObserver(self, selector: #selector(self.keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil) notificationCenter.addObserver(self, selector: #selector(self.keyboardWillChangeFrame(notification:)), name: .UIKeyboardWillChangeFrame, object: nil) notificationCenter.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil) }
もちろん.addObserver(...)
したからにはお行儀よく.removeObserver(...)
しましょう。Viewが表示される時に.add
したのですから、その反対といえばViewが消える時ですね。name
を指定しなければ、全ての通知を解除します。
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) let notificationCenter = NotificationCenter.default notificationCenter.removeObserver(self) }
UITextViewの制約を変更する
今回はオートレイアウトを使っていますので、キーボードが表示される時に、下の余白をキーボードの高さに合わせることで実現します。
まず、Assistant Editor
を表示して、ドキュメントアウトラインのConstraints
から.bottom
をCtrlキーを押しながらEditorにドロップします。
@IBOutlet weak var todoConstraint: NSLayoutConstraint!
これでコードから制約を変更することができるようになります。では関数を実装しましょう。キーボードの高さを取得して、制約にその値を設定します。レイアウトを変更しますので、最後にUIView.layoutIfNeeded()
を呼び出します。
func keyboardWillShow(notification: Notification) { let rect = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let duration: TimeInterval = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as! Double self.todoConstraint.constant = rect.height UIView.animate(withDuration: duration, animations: { () -> Void in self.view.layoutIfNeeded() }) }
キーボードの種類を切り替えたり変換候補が最初に表示される場合などでキーボードの高さが変わる場合でも、.UIKeyboardWillShow
通知が発火します。
反対にキーボードが非表示になる際には、制約に0
を入れます。
では実行してみましょう。UITextViewをタップしてみると、(スクリーンショットでは分かりにくいですが)キーボードを除いた高さになりましたね?
さいごに
最近Swiftに入門したのですが、入門前はキーボード表示でViewのサイズを変更するなんて簡単というか自動でできそう? くらいの勢いでした。こうして記事にして見ると実際簡単そうですが、実は意外とハマったり?
さて、ガラパゴスでは人類の進化に貢献したいエンジニアを大絶賛超募集しています。皆様の応募をお待ちしています。
では、御機嫌よう。
この記事は業務の一環として業務時間を使って書きました。