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

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

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

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

Swift

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

解決済

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

iosClimer
iosClimer

総合スコア20

Xcode

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

Swift

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

2回答

0グッド

0クリップ

401閲覧

投稿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シミュレータで確認

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答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

総合スコア6179

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

iosClimer

2022/04/27 08:01

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

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Xcode

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

Swift

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