質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

871閲覧

IBOutletで定義したNSLayoutConstraintの更新が反映されない

iosClimer

総合スコア20

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2022/04/25 02:24

編集2022/04/25 02:29

前提

AutoLayoutの学習をしております。

一番下のTextFieldの編集時にキーボードに隠れないようにしたいです。

SuperViewとの制約をIBOutletに繋いで、キーボードの出現イベントに合わせて値を更新しようと思ってます。

イメージ説明

実装方法

キーボードの高さを取得しTextFieldとSuperViewとの制約として更新する、という動きを期待してコードを書きました。

class ViewController: UIViewController { @IBOutlet weak var bottomCounstraintOfLastTextField: NSLayoutConstraint! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) } } extension ViewController { ///キーボード出現のタイミングで下の制約を伸ばす @objc private func keyboardWillShow(_ notification: Foundation.Notification) { guard let info = notification.userInfo else { fatalError("Unexpected notification") } ///キーボードフレーム guard let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { fatalError("Found get Keyboard frame") } ///キーボードの高さ let keyboardHeight = keyboardFrame.cgRectValue.height ///キーボード表示アニメーションの時間を取得 guard let animationDuration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { fatalError("Found get Keyboard Animation time")} ///制約を更新 bottomCounstraintOfLastTextField.constant = keyboardHeight ///アニメーションしてレイアウトを更新 UIView.animate(withDuration: animationDuration, animations: { () -> Void in self.view.layoutIfNeeded() }) } ///キーボードが無くなるタイミングで下の制約を39(元に戻す) @objc private func keyboardWillHide(_ notification: Foundation.Notification) { guard let info = notification.userInfo else { fatalError("Unexpected notification") } ///キーボード表示アニメーションの時間を取得 guard let animationDuration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double else { fatalError("Found get Keyboard Animation time")} ///制約を更新 bottomCounstraintOfLastTextField.constant = 39 ///アニメーションしてレイアウトを更新 UIView.animate(withDuration: animationDuration, animations: { () -> Void in self.view.layoutIfNeeded() }) } ///viewをタップするとキーボードを下げる @IBAction func tapGesture(sender: AnyObject) { self.view.endEditing(true) } }

発生している問題

BreakPointで止めて制約の値が更新されてることは確認してます。
が、画面に反映されておらずキーボードに隠れてしまいます。
イメージ説明

試したこと

2016年に発売された本を参考にしております。
ネットで調べて更新する処理を以下のコードに置き換えたらうまく更新されました。

///アニメーションしてレイアウトを更新 UIView.animate(withDuration: animationDuration, animations: { () -> Void in self.scrollView.contentInset.bottom = keyboardHeight self.scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) self.view.layoutIfNeeded() })

このコードで動いてますが、なぜ最初のコードでは反映されないかが気になります。
個人的にはIBOutletで繋いだ値を更新した方が直感的に分かりやすくて好きです。

補足情報(FW/ツールのバージョンなど)

Xcode13.3
iOS15.4シミュレータで確認

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

自己解決

原因は単純にキーボードの上までスクロールする処理を忘れていただけでした。

ScrollViewを使わなくてもキーボードの表示非表示に合わせて位置を変える方法を教えていただきましたが、

  • 対象じゃないTextFieldまで入力時にキーボードの高さ分スクロールしてしまうため、キーボードに隠れる場合のみ位置を変える処理が必要
  • キーボードの表示イベントに噛ませようとするとTextFieldが複数ある場合にどれが入力中かを選定する処理が必要

ということに気づいたので、質問文の「試したこと」に書いた

///アニメーションしてレイアウトを更新 UIView.animate(withDuration: animationDuration, animations: { () -> Void in self.scrollView.contentInset.bottom = keyboardHeight self.scrollView.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) self.view.layoutIfNeeded() })

で落ち着きました。

ご協力いただきありがとうございました。

投稿2022/04/27 09:39

iosClimer

総合スコア20

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ScrollViewのコンテンツ内に配置されているUI部品のbottom制約を大きくしたら、その制約に応じてコンテンツのサイズが大きくなるだけで、スクロービュー内のコンテンツの表示位置が変わることにはならないと思います。

キーボードの出現に応じてbottom制約を大きくする方法は、スクロールビューを使用せず、画面の下端からの距離を制約に設定している場合に使える方法だと思います。

ちなみに、次のURLにあるような方法で、キーボードの出現に応じてルートview(self.view)の表示位置をずらす方法なら、画面内の構成がどのようになっていても(ScrollViewを使用してもしなくても、AutoLayoutを使用してもしなくても)同じ方法でUI部品の表示位置をずらすことができると思います。

https://orangelog.site/swift/slide-view-with-keyboard/

投稿2022/04/26 13:03

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

iosClimer

2022/04/27 08:01

確かに、コンテンツのサイズが大きくなるだけでキーボードの上までスクロールはしてくれませんね。一応、キーボード表示中に伸びた分を手動でスクロールすることはできました。 ただ、添付いただいた記事のコードを試したところ、表示位置を変えなくても良いもの(今回の例でいくと一番上のTextFieldなど)も入力開始時にキーボードの高さ分移動してしまい、端末の上を過ぎてしまいました。。。 別途、キーボードに隠れるかどうかの処理を挟む必要がありました。 もう少し取り組んでみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問