Swiftを使用してキーボードでビューを移動する


278

ビューの下半分にテキストフィールドがあるアプリがあります。つまり、テキストフィールドに入力すると、キーボードがテキストフィールドを覆います。

入力中にビューを上に移動して、入力内容を確認し、キーボードが消えたら元の場所に戻すにはどうすればよいですか?

私は至る所を見てきましたが、すべての解決策はObj-Cにあるようですが、まだ完全に変換することはできません。

どんな助けでも大歓迎です。


これを行う最良の方法は、コンテンツをUIScrollView内に配置し、スクロールビューのcontentInsetプロパティを、表示されているときにキーボードの高さで調整することです。キーボードの高さは絶対に想定しないでください。「キーボードが表示されます」通知の値を使用してください。
nielsbot 2015年

1
実際には、Apple社のドキュメントには、「キーボードの管理」の下に、これを行う方法を教えてくれ:developer.apple.com/library/ios/documentation/StringsTextFonts/...
nielsbot

11
以下のすべての回答では、1つのケースが考慮されていないと思います。複数のテキストフィールドがあり、その一部が画面の上部にある場合はどうなりますか?いつでもユーザーは、私は、正しい答えはかどうかを検出する必要がありますかなり確信している、それがスクリーンを超えて上がると、そのテキストフィールドをタップit is actually needed to scroll view up when keyboard appears
theDC

この答えは、キーボードは現在編集中のテキストフィールドがキーボードと同じスペースを占有しているか否かをチェックすることによって表示されたときに、実際にビューをスクロールアップするために必要とされるかどうかを検出することができます:stackoverflow.com/a/28813720/6749410
HirdayGupta

回答:


709

1つのtextFieldから別のtextFieldへの切り替えを処理せずに解決策を次に示します。

 override func viewDidLoad() {
        super.viewDidLoad()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)            
    }   

func keyboardWillShow(notification: NSNotification) {            
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }            
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

これを解決するには、2つの関数keyboardWillShow/Hideを次のものに置き換えます。

func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

func keyboardWillHide(notification: NSNotification) {
    if view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

SWIFT 3.0用に編集:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

SWIFT 4.0用に編集:

override func viewDidLoad() {
    super.viewDidLoad()            
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)    
}

@objc func keyboardWillShow(notification: NSNotification) {        
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }        
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

SWIFT 4.2用に編集:

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)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

56
キーボードが表示されているときにユーザーが別のテキストフィールドに触れると、ビューがさらに押し上げられ、黒い領域(キーボードのサイズ)が発生します。キーボードが表示されているかどうかを追跡する変数を設定して、問題を修正する必要があります。 。たとえばkeyboardPresent == trueの場合、ビューの原点などを移動しないでください
jonprasetyo

3
@Matthew Linはブール値を使用するため、keyboardWillShow関数とhide関数は1
回し

11
提案は1つだけなので、私が行ったような多くのデバッグを行う必要はありません。同じ画面に複数のuitextfieldsがある場合、キーボードのサイズは変化する可能性があるため(設定に基づいて一部の入力に対する提案は表示されません)、毎回self.view.frame.origin.y = 0を設定することをお勧めしますキーボードを閉じます。たとえば、メールのテキストフィールドの推測が表示されるため、キーボードのサイズが大きくなり、パスワードフィールドの候補が表示されないため、キーボードのサイズが小さくなります。
Vandan Patel 2016

36
キーボードサイズを取得するときUIKeyboardFrameEndUserInfoKeyではなく使用する必要がありUIKeyboardFrameBeginUserInfoKeyます。現時点では理由はわかりませんが、前者の方がより一貫した結果が得られます。
jshapy8 2017年

3
に置き換えUIKeyboardFrameBeginUserInfoKeyてくださいUIKeyboardFrameEndUserInfoKey。最初のものはキーボードの開始フレームを提供し、時々ゼロになりますが、2番目のものはキーボードの終了フレームを提供します。
Arnab 2018年

90

コードさえ必要としない最も簡単な方法:

  1. まだSpringアニメーションフレームワークを使用していない場合は、KeyboardLayoutConstraint.swiftをダウンロードして、ファイルをプロジェクトに追加(ドラッグアンドドロップ)します。
  2. ストーリーボードで、ビューまたはテキストフィールドの下部制約を作成し、制約を選択(ダブルクリック)し、IDインスペクターで、そのクラスをNSLayoutConstraintからKeyboardLayoutConstraintに変更します。
  3. できた!

オブジェクトはキーボードと同期して自動で上に移動します。


4
あなたもサイズインスペクタに行くことができます下の制約を選択するには、リストに制約をダブルクリック- raywenderlich.com/wp-content/uploads/2015/09/...
gammachill

3
これは私にとって完璧に機能しました。これは文字通り2ステップのプロセスです。1. KeyboardLayoutConstraint.swiftを追加します。2。ストーリーボードで、ビューまたはテキストフィールドの下部制約を作成します。注:制約を削除して、ビューまたはテキストフィールドの下部に制約を1つだけ追加し、そのクラスをNSLayoutConstraintからKeyboardLayoutConstraintに変更しました。次に、上記のビュー/テキストフィールドなど、そのアイテムからの制約を単一のKeyboardLayoutConstraintでアイテムに接続しました。その結果、キーボードが表示/非表示になると、ビュー内のすべてのアイテムが上下に移動しました
Brian

4
これが最良の解決策です。提供されたコードは、アニメーションの長さや曲線、キーボードのサイズなどの値をハードコードしません。分かりやすいです。
miguelSantirso 2017

3
これは私にとってはうまくいきますが、キーボードの上部とscrollViewの下部の間に余分な50pxのスペースができます。私が使用しているセーフエリアの下部の制約が原因であるかどうか疑問に思っています。誰かがこれに遭遇しましたか?
Clifton Labrum

1
これは素晴らしい答えでした。とてもクールなデザイン。1つの提案:テキストビュー/テキストフィールドがテーブルビューセルにある場合、ユーザーがEnterキーを押して次のテキストフィールドに移動するたびに、この制約を持つビューがぎこちなくジャンプすることに気付くでしょう。アニメーションをラップしDispatchQueue.main.async {}て修正できます。よくできました!いいぞ!
ScottyBlades

68

このスレッドでよくある答えの1つは、次のコードを使用します。

func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

ビューを静的な量だけオフセットすることには明らかな問題があります。1つのデバイスでは見栄えがよくなりますが、他のサイズの構成では見栄えが悪くなります。キーボードの高さを取得し、それをオフセット値として使用する必要があります。

これは、すべてのデバイス機能し、ユーザーが入力中に予測テキストフィールドを非表示にするエッジケースを処理するソリューションです。

解決

以下で注意することが重要です。オブジェクトパラメータとしてself.view.windowを渡しています。これにより、キーボードの高さなどのデータが提供されます。

@IBOutlet weak var messageField: UITextField!

override func viewDidLoad() {
    super.viewDidLoad()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: self.view.window)
}

func keyboardWillHide(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    self.view.frame.origin.y += keyboardSize.height
}

すべてのデバイスで見栄えをよくし、ユーザーが予測テキストフィールドを追加または削除する場合を処理します。

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!
    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y -= keyboardSize.height
        })
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
}

オブザーバーを削除

不要なメッセージが送信されないようにするには、ビューを離れる前にオブザーバを削除することを忘れないでください。

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: self.view.window)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: self.view.window)
}

コメントからの質問に基づいて更新:

2つ以上のテキストフィールドがある場合は、view.frame.origin.yがゼロになっているかどうかを確認できます。

func keyboardWillShow(sender: NSNotification) {
    let userInfo: [NSObject : AnyObject] = sender.userInfo!

    let keyboardSize: CGSize = userInfo[UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
    let offset: CGSize = userInfo[UIKeyboardFrameEndUserInfoKey]!.CGRectValue.size

    if keyboardSize.height == offset.height {
        if self.view.frame.origin.y == 0 {
            UIView.animateWithDuration(0.1, animations: { () -> Void in
                self.view.frame.origin.y -= keyboardSize.height
            })
        }
    } else {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.frame.origin.y += keyboardSize.height - offset.height
        })
    }
     print(self.view.frame.origin.y)
}

1
複数のテキストフィールドを処理する場合、ビューが上に移動し続け、下に戻らない
Mugunthan Balakrishnan

テキストフィールドを考慮するために条件を変更する必要があります
Dan Beaulieu

レスポンスのおかげで、私は、スタックオーバーフローの上のこのスレッドで探していた答えは見つからstackoverflow.com/questions/1126726/...
Mugunthanバラクリシュナン

@MugunthanBalakrishnanこれを取り上げてくれてありがとう、私は解決策を追加しました。
Dan Beaulieu

こんにちは、バグがあります。オブザーバーは、viewWillDisappearで呼び出された後、ビューから削除されません。この行「NSNotificationCenter.defaultCenter()。removeObserver(self、name:UIKeyboardWillHideNotification、object:self.view.window)」を「NSNotificationCenter.defaultCenter()。removeObserver(self、name:UIKeyboardWillHideNotification、object:nil)」に置き換えて、オブザーバーが削除されました
rudald

29

これをビューコントローラーに追加します。魅力のように機能します。値を調整するだけです。

override func viewDidLoad() {
    super.viewDidLoad()        
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil);
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil);
}

@objc func keyboardWillShow(sender: NSNotification) {
    self.view.frame.origin.y -= 150
}
@objc func keyboardWillHide(sender: NSNotification) {
    self.view.frame.origin.y += 150
}

これは私にとってはうまくいきます。しかし、それは少しぎこちないです。これをどのようにしてスムーズに上に移動できますか?現在すべてに対してこれを行っているため、テキストフィールドの1つにのみ適用する方法もあります。:(
DannieCoderBoi

2
「自動レイアウト」では機能しない可能性があるため、無効にすることを検討してください。
Teodor Ciuraru、2015

1
autolayout @Joshでファンキーな動作が発生します。これは間違いです
Mike

5
これを行わないでください!キーボードが特定のサイズであるとは限りません。
nielsbot 2015年

2
keyboardSizeを使用する必要があります。デバイスにアクセサリビューがあり、キーボードの高さが異なる場合はどうなりますか?分離したキーボード?
xtrinch

25

1つのページのさまざまなキーボードとさまざまなテキストビュー/フィールドで動作するように、回答の1つを少し改善しました。

オブザーバーを追加:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func keyboardWillHide() {
    self.view.frame.origin.y = 0
}

func keyboardWillChange(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        if YOURTEXTVIEW.isFirstResponder {
            self.view.frame.origin.y = -keyboardSize.height
        }
    }
}

オブザーバーを削除します。

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}

3
この解決策は、受け入れられた回答よりもうまく機能します。受け入れられた答えは、私にとってバグであるキーボードを一度だけ示します:)
Masih

これはXcode 10.1とiOS 12で機能します。受け入れられた回答は無効になります。
Zeeshan

これは素晴らしい答えです。追加するのは、新しいデバイス(X、XSなど)の下部の安全領域を追跡して、それを考慮に入れることだけです。
Munib

@Munib stackoverflow.com/a/54993623/1485230を参照その他の問題には、ビューがアニメーション化しない、キーボードの高さの変更が追跡されないなどがあります。
Antzi

textFieldがビューの上部にある場合はどうなりますか?私は原点Y = 0 .. ??のテキストフィールドがあるかどうかを意味します その後、textFieldが上がり、表示され
ませ

18

広告やプロモーション、スパムではなく、良い解決策です。この質問には30近くの回答があることを知っています。ショックを受けて、あなたのために、そしてそれ以上にすべてを行うこの美しいGitHubプロジェクトについて誰も一度も言及しませんでした。すべての答えはビューを上に移動するだけです。このIQKeyboardManagerですべての問題を解決しました。それは13000以上の星があります。
迅速に使用している場合は、これをポッドファイルに追加するだけです

pod 'IQKeyboardManagerSwift'

そしてあなたのAppDelegate.swift内 import IQKeyboardManagerSwift

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

      IQKeyboardManager.shared.enable = true // just add this line

      return true
    }
}

これIQKeyboardManager.shared.enable = trueを有効にするための行を追加し
ます。このソリューションは、本番環境で使用する場合に必須です。


これは本当に良いですが、私にとって最新バージョンは機能しません。6.2.1 import IQKeyboardManagerを使用しIQKeyboardManager.shared().isEnabled = true、AppDelegate としてインポートして使用しました
Dhanu K

2
そして、これは複数の編集テキストを使用するときに素晴らしく機能します。これは私の時間を節約しました
Dhanu K

1
この素晴らしいライブラリを指摘してくれてありがとう。このライブラリは、Appleがソリューションを提供したことがないキーボード関連のすべてのナンセンスに対する最終的な回答です。今、私はすべてのプロジェクトで新旧を問わず使用し、このキーボードの表示、非表示、非表示、または非表示にする方法、およびそれが重複している理由、そして問題が原因となって以来、時間と頭痛を節約しますiPhone向けのプログラミングをしている日。
ジーシャン

1
ここにある他のソリューションと同様に、テキストフィールドを移動するための独自のコードを書きました。IQKeyboardManagerは非常に優れているので、これから組み込みます。フレームワークが最新の状態に保たれていない場合に備えて、コードを手元に置いておきます。
TMリンチ

@DhanuK、このライブラリを見つけただけで完璧に動作し、苦労しません。アプリのデリゲートコードがIQKeyboardManager.shared.enable = true
adougiesに

15

黒い画面エラー (Swift 4および4.2)の場合

黒い画面の問題を修正しました。検証済みのソリューションでは、タップ後にキーボードの高さが変化し、これにより黒い画面が表示されます。

UIKeyboardFrameBeginUserInfoKeyの代わりにUIKeyboardFrameEndUserInfoKey を使用する必要がある

var isKeyboardAppear = false

override func viewDidLoad() {
    super.viewDidLoad() 
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if !isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y == 0{
                self.view.frame.origin.y -= keyboardSize.height
            }
        }
        isKeyboardAppear = true
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if isKeyboardAppear {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            if self.view.frame.origin.y != 0{
                self.view.frame.origin.y += keyboardSize.height
            }
        }
         isKeyboardAppear = false
    }
}

タブバーがある場合は機能しません。タブバーの高さを計算する必要があります。そうしないと、キーボードとビューの間に黒い画面のギャップが生じます。
Ankur Lahiry

これは、キーボードがiPhone X以降にあった黒い領域を修正しません。キーボードが表示されたり消えたりするたびに、メインビューがスライドし続けます。
エジソン

14

すべての回答がキーボードの高さの値によってビュー自体を移動しているのがわかります。さて、私は精巧な答えを持っています。これは、制約を使用している場合に役立つ可能性があります。つまりautolayout、事前定義された値によって制約値(たとえば、下部または上部の制約)を変更することによってビューを移動するか、キーボードのサイズ値を使用できます。

この例では、テキストフィールドからボトムレイアウトビューへのボトム制約を使用し、初期値は175です。

@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()        
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil);
}

func keyboardWillShow(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 260
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

func keyboardWillHide(notification: NSNotification) {
    //To retrieve keyboard size, uncomment following line
    //let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
    bottomConstraint.constant = 175
    UIView.animateWithDuration(0.3) {
        self.view.layoutIfNeeded()
    }
}

こんにちは、TableViewも含むビューに配置したときにこれが機能しない理由を教えてください。CollectionViewが含まれている場合、同じシナリオで正常に動作します。
elarcoiris

9

KeyboardWillHideNotificationの定義方法に若干の変更がありました。

このソリューションはSwift 4.2で機能します。

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)


@objc func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

@objc func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        self.view.frame.origin.y += keyboardSize.height
    }
}

2
textFieldがビューの上部にある場合はどうなりますか?私は原点Y = 0 .. ??のテキストフィールドがあるかどうかを意味します その後、textFieldが上がり、表示され
ませ

7

Swift 5.0:

4〜5時間の戦いの後、魅力的なように機能するシンプルなコードを備えたUIViewControllerのシンプルな拡張機能が付属しました

* TextFieldがキーボードの上にある場合、ビューは移動しません。

* NSLayoutConstraintに定数値を設定する必要はありません

*サードパーティのライブラリは必要ありません

*アニメーションコードは必要ありません

*テーブルビューでも機能します

*これは自動レイアウト/自動サイズ変更で機能します

extension UIViewController {
    func addKeyboardObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardNotifications(notification:)),
                                               name: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil)
    }

    func removeKeyboardObserver(){
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

    // This method will notify when keyboard appears/ dissapears
    @objc func keyboardNotifications(notification: NSNotification) {

        var txtFieldY : CGFloat = 0.0  //Using this we will calculate the selected textFields Y Position
        let spaceBetweenTxtFieldAndKeyboard : CGFloat = 5.0 //Specify the space between textfield and keyboard


        var frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        if let activeTextField = UIResponder.currentFirst() as? UITextField ?? UIResponder.currentFirst() as? UITextView {
            // Here we will get accurate frame of textField which is selected if there are multiple textfields
            frame = self.view.convert(activeTextField.frame, from:activeTextField.superview)
            txtFieldY = frame.origin.y + frame.size.height
        }

        if let userInfo = notification.userInfo {
            // here we will get frame of keyBoard (i.e. x, y, width, height)
            let keyBoardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
            let keyBoardFrameY = keyBoardFrame!.origin.y
            let keyBoardFrameHeight = keyBoardFrame!.size.height

            var viewOriginY: CGFloat = 0.0
            //Check keyboards Y position and according to that move view up and down
            if keyBoardFrameY >= UIScreen.main.bounds.size.height {
                viewOriginY = 0.0
            } else {
                // if textfields y is greater than keyboards y then only move View to up
                if txtFieldY >= keyBoardFrameY {

                    viewOriginY = (txtFieldY - keyBoardFrameY) + spaceBetweenTxtFieldAndKeyboard

                    //This condition is just to check viewOriginY should not be greator than keyboard height
                    // if its more than keyboard height then there will be black space on the top of keyboard.
                    if viewOriginY > keyBoardFrameHeight { viewOriginY = keyBoardFrameHeight }
                }
            }

            //set the Y position of view
            self.view.frame.origin.y = -viewOriginY
        }
    }
}

このUIResponderの拡張機能を追加して、選択されているTextFieldを取得します。

extension UIResponder {

    static weak var responder: UIResponder?

    static func currentFirst() -> UIResponder? {
        responder = nil
        UIApplication.shared.sendAction(#selector(trap), to: nil, from: nil, for: nil)
        return responder
    }

    @objc private func trap() {
        UIResponder.responder = self
    }
}

次に、これを任意のViewControllerで使用します

   override func viewWillAppear(_ animated: Bool) {
        self.addKeyboardObserver()
    }

    override func viewWillDisappear(_ animated: Bool) {
        self.removeKeyboardObserver()
    }


これは最良のソリューションのように見えましたが、いくつかのバグがあります。1、テキストフィールドは上に移動しますが、入力を開始すると、もう少し上に移動します。2、横向きでtextFieldを入力すると、左にジャンプすることがあります。
ダレン

@ダーレン私はこれらのバグを理解しようとしていますが、見つかりませんでした。どのバージョン/デバイスでこれらのバグが発生したのかを教えてください... ??
サイファンナダフ

6

Swift 3では、すべてのビューコントローラーで一定の動作が必要だったため、UIViewControllerサブクラスを作成しました。

class SomeClassVC: UIViewController {

  //MARK: - Lifecycle
  override func viewDidLoad() {
    super.viewDidLoad()

    addKeyboardObservers()
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    removeKeyboardObservers()
  }

  //MARK: - Overrides
  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    view.endEditing(true)
  }

  //MARK: - Help
  func addKeyboardObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
  }

  func removeKeyboardObservers() {
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: self.view.window)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: self.view.window)
  }

  func keyboardWillShow(notification: NSNotification) {
    let keyboardHeight = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.height
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = -1 * keyboardHeight!
      self.view.layoutIfNeeded()
    })
  }

  func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.1, animations: { () -> Void in
      self.view.window?.frame.origin.y = 0
      self.view.layoutIfNeeded()
    })
  }

  func resignTextFieldFirstResponders() {
    for textField in self.view.subviews where textField is UITextField {
      textField.resignFirstResponder()
    }
  }

  func resignAllFirstResponders() {
      view.endEditing(true)
  }
}

Pavleのソリューションに触発されて、私はそれをアップグレードして、残りの使用可能なスペースの一定の割合でキーボードを自動的に上げ、適切なレイアウトのために再帰的にフォーカスされたフィールドを見つけました。ここで入手
Noor Dawod 2017

タブバーもウィンドウと共に移動します!:(
Alfi

6

検証済みの回答はテキストフィールドの位置考慮せずいくつかのバグがあります(二重変位、最初の位置に戻らない、texfieldがビューの上にある場合でも変位...)

アイデアは:

  • フォーカスTextFieldの絶対Y位置を取得する
  • キーボードの高さを取得する
  • ScreenHeightを取得する
  • 次に、キーボードの位置とテキストフィールドの間の距離を計算します(<0->の場合、ビューを上に移動します)
  • UIView.frame.origin.y-= ..の代わりにUIView.transformを使用すると、UIView.transform = .identityで元の位置に戻るのが簡単になります

次に、必要な場合にのみビューを移動し、特定の変位をオーダーで移動して、フォーカスされたtexFieldをキーボードの真上に移動します。

ここにコードがあります:

スウィフト4

class ViewController: UIViewController, UITextFieldDelegate {

var textFieldRealYPosition: CGFloat = 0.0

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(VehiculeViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

  // Delegate all textfields

}


@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let distanceBetweenTextfielAndKeyboard = self.view.frame.height - textFieldRealYPosition - keyboardSize.height
        if distanceBetweenTextfielAndKeyboard < 0 {
            UIView.animate(withDuration: 0.4) {
                self.view.transform = CGAffineTransform(translationX: 0.0, y: distanceBetweenTextfielAndKeyboard)
            }
        }
    }
}


@objc func keyboardWillHide(notification: NSNotification) {
    UIView.animate(withDuration: 0.4) {
        self.view.transform = .identity
    }
}


func textFieldDidBeginEditing(_ textField: UITextField) {
  textFieldRealYPosition = textField.frame.origin.y + textField.frame.height
  //take in account all superviews from textfield and potential contentOffset if you are using tableview to calculate the real position
}

}


とても良い!(viewDidLoadには、「ViewController」だけでなく「VehiculeViewController」があります)。
ルネ

より完全で有用な答え。ありがとうございました!キーボードの一貫したサイズが得られるため、キーボードチェックを次のように呼び出すことをお勧めします。 .size
ベン

4

他の答えには、トップの一部をビューからカットすることが含まれていることに気付きました。コンテンツをカットせずに単にビューのサイズを変更したい場合は、この方法を試してください:)

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.setTranslatesAutoresizingMaskIntoConstraints(true)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height - keyboardSize.height)
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.collectionView.setTranslatesAutoresizingMaskIntoConstraints(false)
        self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.height + keyboardSize.height)
    }
}

4

初心者のための私の2セント:上記のサンプルでは、​​誰かが座標を変更したり、他の人が「自動サイズ変更マスク」を使用したり、その他の制約を加えたりしています:

Appleが言うように、これら3つのタイプのロジックを混在させないでください。ストーリーボードに制約がある場合は、x / yを変更しないでください。間違いなく動作しません。


4

したがって、他の答えはどれも正しく理解されていないようです。

iOSのGood Behavioredキーボードは、

  • キーボードのサイズが変更されたときに自動的にサイズを変更します(YES IT CAN)
  • キーボードと同じ速度でアニメート
  • キーボードと同じ曲線を使用してアニメートする
  • 必要に応じて安全な場所を尊重してください。
  • iPad /ドッキング解除モードでも動作します

私のコードはNSLayoutConstraint宣言された@IBOutlet

@IBOutlet private var bottomLayoutConstraint: NSLayoutConstraint!

変換、ビューオフセットなどを使用することもできます。制約条件を使用すると簡単です。これは、制約を下部に設定することで機能します。定数が0 / Notでない場合は、コードを変更する必要がある場合があります。

これがコードです:

// In ViewDidLoad
    NotificationCenter.default.addObserver(self, selector: #selector(?MyViewController.keyboardDidChange), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)


@objc func keyboardDidChange(notification: Notification) {
    let userInfo = notification.userInfo! as [AnyHashable: Any]
    let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! NSNumber
    let animationCurve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as! NSNumber
    bottomLayoutConstraint.constant = view.frame.height - endFrame.origin.y - view.safeAreaInsets.bottom // If your constraint is not defined as a safeArea constraint you might want to skip the last part.
    // Prevents iPad undocked keyboard.
    guard endFrame.height != 0, view.frame.height == endFrame.height + endFrame.origin.y else {
        bottomLayoutConstraint.constant = 0
        return
    }
    UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: animationCurve.intValue)!)
    UIView.animate(withDuration: animationDuration.doubleValue) {
        self.view.layoutIfNeeded()
        // Do additional tasks such as scrolling in a UICollectionView
    }
}

3

キーボードを開いたときのすべてのガイの更新テーブルビューの高さに対する100%の完全な回答

Swift4.2の場合

   override func viewDidLoad() {
      super.viewDidLoad()
      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)

      NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
   }

   @objc func keyboardWillShow(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {

        var userInfo = notification.userInfo!
        var keyboardFrame:CGRect = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        keyboardFrame = self.view.convert(keyboardFrame, from: nil)

        var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset
    }
}

   @objc func keyboardWillHide(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tbl.contentInset = contentInset
    }
}

スウィフト3.2

    override func viewDidLoad() {
          super.viewDidLoad()

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)

           NotificationCenter.default.addObserver(self, selector: #selector(RecipeVC.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
    }
    func keyboardWillShow(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         //self.view.frame.origin.y -= keyboardSize.height
         var userInfo = notification.userInfo!
         var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
          keyboardFrame = self.view.convert(keyboardFrame, from: nil)

          var contentInset:UIEdgeInsets = self.tbl.contentInset
          contentInset.bottom = keyboardFrame.size.height
          self.tbl.contentInset = contentInset

       }
    }

    func keyboardWillHide(notification: NSNotification) {
         if ((notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue) != nil {
         let contentInset:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
         self.tbl.contentInset = contentInset
         }
    }

これが最良の答えです。tblはtableViewである必要があり、パディングを追加しました:contentInset.bottom = keyboardFrame.size.height + 10
iphaaw

2

スウィフト3

func textFieldDidBeginEditing(_ textField: UITextField) { // became first responder

    //move textfields up
    let myScreenRect: CGRect = UIScreen.main.bounds
    let keyboardHeight : CGFloat = 216

    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var needToMove: CGFloat = 0

    var frame : CGRect = self.view.frame
    if (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height > (myScreenRect.size.height - keyboardHeight - 30)) {
        needToMove = (textField.frame.origin.y + textField.frame.size.height + UIApplication.shared.statusBarFrame.size.height) - (myScreenRect.size.height - keyboardHeight - 30);
    }

    frame.origin.y = -needToMove
    self.view.frame = frame
    UIView.commitAnimations()
}

func textFieldDidEndEditing(_ textField: UITextField) {
    //move textfields back down
    UIView.beginAnimations( "animateView", context: nil)
    var movementDuration:TimeInterval = 0.35
    var frame : CGRect = self.view.frame
    frame.origin.y = 0
    self.view.frame = frame
    UIView.commitAnimations()
}

2

スウィフト4:

キーボードを非表示にしても、ページの下部まで(部分的にしか)ビューが返されないという、最も受け入れられている回答に問題がありました。これは私にとってはうまくいきました(Swift 4用に更新されました)。

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideKeyboardWhenTappedAround()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0{
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y != 0{
            self.view.frame.origin.y = 0
        }
    }
}

textFieldがビューの上部にある場合はどうなりますか?私は原点Y = 0 .. ??のテキストフィールドがあるかどうかを意味します その後、textFieldが上がり、表示され
ませ

2

@Borisの回答に似ていますが、Swift 5の場合

override func 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)
}

@IBAction func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

@IBAction func keyboardWillHide(notification: NSNotification) {
    if self.view.frame.origin.y != 0 {
        self.view.frame.origin.y = 0
    }
}

1

これが私の解決策です(実際には、このコードはビューにテキストフィールドがいくつかある場合のコードです。これは、テキストフィールドが1つの場合にも機能します)。

class MyViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var firstTextField: UITextField!
@IBOutlet weak var secondTextField: UITextField!

var activeTextField: UITextField!
var viewWasMoved: Bool = false


override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(PrintViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil)
}

override func viewDidDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func textFieldDidBeginEditing(textField: UITextField) {
    self.activeTextField = textField
}

func textFieldDidEndEditing(textField: UITextField) {
    self.activeTextField = nil
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    return true
}


func keyboardWillShow(notification: NSNotification) {

    let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()

    var aRect: CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height

    let activeTextFieldRect: CGRect? = activeTextField?.frame
    let activeTextFieldOrigin: CGPoint? = activeTextFieldRect?.origin

    if (!CGRectContainsPoint(aRect, activeTextFieldOrigin!)) {
        self.viewWasMoved = true
        self.view.frame.origin.y -= keyboardSize!.height
    } else {
        self.viewWasMoved = false
    }
}

func keyboardWillHide(notification: NSNotification) {
    if (self.viewWasMoved) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

DelegateをtextFieldsに設定することを忘れないでください
SwingerDinger

(!CGRectContainsPoint(aRect、newOrgin!)&&!self.viewWasMoved)
KingofBliss

フレームのリセット時にself.viewWasMoved = falseを追加
KingofBliss

1

Swift 3用に更新...

他の人が言ったように、コントローラのviewDidLoad()メソッドに次のように通知オブザーバを追加する必要があります:

NotificationCenter.default.addObserver(forName: .UIKeyboardWillShow, object: nil, queue: nil)
    { notification in
    self.keyboardWillShow(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardWillHide, object: nil, queue: nil)
    { notification in
    self.keyboardWillHide(notification)
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidShow, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

NotificationCenter.default.addObserver(forName: .UIKeyboardDidHide, object: nil, queue: nil)
    { _ in
    self.enableUserInteraction()
    }

必要に応じてオブザーバーを削除することを忘れないでください(私はviewWillDisappear()メソッドで削除します)

NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardDidHide, object: nil)

次に、showメソッドとhideメソッドを実装します-アプリに対話イベントを無視するように指示する行(beginIgnoringInteractionEvents)に注意してください。これがないと、ユーザーがフィールドまたはスクロールビューをタップして、もう一度シフトが発生し、UIにひどい不具合が発生する可能性があるため、これは重要です。キーボードの表示と非表示の前に対話イベントを無視すると、これを防ぐことができます。

func keyboardWillShow(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y -= keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top += keyboardSize.height
        }
    }

func keyboardWillHide(notification: Notification)
    {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue
        {
        UIApplication.shared.beginIgnoringInteractionEvents()
        self.view.frame.origin.y += keyboardSize.height
        // add this line if you are shifting a scrollView, as in a chat application
        self.timelineCollectionView.contentInset.top -= keyboardSize.height
        }
    }

最後に、ユーザーインタラクションを再度有効にします(このメソッドは、キーボードのdidShowまたはdidHideの後に発生します)。

func enableUserInteraction()
    {
    UIApplication.shared.endIgnoringInteractionEvents()
    }

1

Swift 3コード

var activeField: UITextField?

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(ProfileViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func textFieldDidBeginEditing(_ textField: UITextField){
    activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if (self.activeField?.frame.origin.y)! >= keyboardSize.height {
            self.view.frame.origin.y = keyboardSize.height - (self.activeField?.frame.origin.y)!
        } else {
            self.view.frame.origin.y = 0
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    self.view.frame.origin.y = 0
}

1

同じVCに2つ以上のテキストフィールドがあり、ユーザーがそれらの1つをタップしてから、関数keyboardWillHideを呼び出さずにもう1つをタップすると、ビューがもう一度上に移動しますが、これは必要ないためです。私が編集した回答のコードを使用して、キーボード、キーボードの高さの空白スペース、そしてビューが表示されます。

override func viewDidLoad() {       
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y -= keyboardSize.height
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y += keyboardSize.height
    }
}

これを解決するには、2つの関数「KeyboardWillShow / Hide」を次のように置き換えます。

func keyboardWillShow(notification: NSNotification) {
 if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
    if view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
        }
    }
}

func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        if view.frame.origin.y != 0 {
            self.view.frame.origin.y += keyboardSize.height
        }
    }
}

textFieldがビューの上部にある場合はどうなりますか?私は原点Y = 0 .. ??のテキストフィールドがあるかどうかを意味します その後、textFieldが上がり、表示され
ませ

1

@Borisのソリューションは非常に優れていますが、ビューが破損することがあります。

完璧な配置のために、以下のコードを使用してください

override func viewDidLoad() {
super.viewDidLoad()            
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)}

関数:

@objc func keyboardWillShow(notification: NSNotification) {        
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y == 0{
        self.view.frame.origin.y -= keyboardSize.height
    }
}}    

そして、

@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
    if self.view.frame.origin.y != 0{
        self.view.frame.origin.y = 0 
    }
} }

0

このビデオチュートリアルは最高です。7分の長さで、それは非常に理にかなっています。複数のテキストフィールドがあり、その特定のテキストフィールドがタップされたときにスクロールビューで「x」ピクセルだけ移動する場合の、このような単純なソリューション。

https://youtu.be/VuiPGJOEBH4

これらの手順のみ:

-ビューの端に制限されているスクロールビュー内にすべてのテキストフィールドを配置します。

-すべてのテキストフィールドとスクロールビューをデリゲートとしてビューコントローラに接続します。

-すべてのテキストフィールドとスクロールビューをIBOutletで接続します。

class ViewController: UIViewController, UITextFieldDelegate {

-UITextFieldDelegateプロトコルをクラスに追加します

@IBOutlet var stateAddress: UITextField!
@IBOutlet var zipAddress: UITextField!
@IBOutlet var phoneNumber: UITextField!
@IBOutlet var vetEmailAddress: UITextField!    
@IBOutlet weak var scrollView: UIScrollView!

-UITextFieldDelegateメソッドをSwiftファイルに追加します。

func textFieldShouldReturn(textField: UITextField) -> Bool {

    textField.resignFirstResponder()
    return true
}


func textFieldDidBeginEditing(textField: UITextField) {

    if (textField == self.stateAddress) {
        scrollView.setContentOffset(CGPointMake(0, 25), animated: true)
    }
    else if (textField == self.zipAddress) {
        scrollView.setContentOffset(CGPointMake(0, 57), animated: true)
    }
    else if (textField == self.phoneNumber) {
        scrollView.setContentOffset(CGPointMake(0, 112), animated: true)
    }
    else if (textField == self.vetEmailAddress) {
        scrollView.setContentOffset(CGPointMake(0, 142), animated: true)
    }
}

func textFieldDidEndEditing(textField: UITextField) {

    scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}

最初の方法は、キーボードの[戻る]ボタンをアクティブにして、キーボードを非表示にするだけです。2つ目は、特定のテキストフィールドをタップして、スクロールビューがスクロールする距離のyオフセットを設定するときです(私のビューコントローラー25、57、112、142のy位置に基づいています)。最後は、キーボードから離れてタップすると、スクロールビューは元の場所に戻ります。

この方法でビューピクセルを完璧にしました!


0

この機能はIosに組み込まれていますが、外部で行う必要があります。
以下のコードを挿入します
* textFieldがキーボードの下にあるときにビューを移動するには、
* textFieldがキーボードの上にあるときにビューを移動しない
*必要に応じて、キーボードの高さに基づいてビューを移動する
これはすべてのケースで機能し、テストされています。

import UIKit

class NamVcc: UIViewController, UITextFieldDelegate
{
    @IBOutlet weak var NamTxtBoxVid: UITextField!

    var VydTxtBoxVar: UITextField!
    var ChkKeyPadDspVar: Bool = false
    var KeyPadHytVal: CGFloat!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        NamTxtBoxVid.delegate = self
    }

    override func viewWillAppear(animated: Bool)
    {
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadVyd(_:)),
            name:UIKeyboardWillShowNotification,
            object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: #selector(TdoWenKeyPadHyd(_:)),
            name:UIKeyboardWillHideNotification,
            object: nil);
    }

    func textFieldDidBeginEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = TxtBoxPsgVar
    }

    func textFieldDidEndEditing(TxtBoxPsgVar: UITextField)
    {
        self.VydTxtBoxVar = nil
    }

    func textFieldShouldReturn(TxtBoxPsgVar: UITextField) -> Bool
    {
        self.VydTxtBoxVar.resignFirstResponder()
        return true
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
    {
        view.endEditing(true)
        super.touchesBegan(touches, withEvent: event)
    }

    func TdoWenKeyPadVyd(NfnPsgVar: NSNotification)
    {
        if(!self.ChkKeyPadDspVar)
        {
            self.KeyPadHytVal = (NfnPsgVar.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().height

            var NonKeyPadAraVar: CGRect = self.view.frame
            NonKeyPadAraVar.size.height -= self.KeyPadHytVal

            let VydTxtBoxCenVal: CGPoint? = VydTxtBoxVar?.frame.origin

            if (!CGRectContainsPoint(NonKeyPadAraVar, VydTxtBoxCenVal!))
            {
                self.ChkKeyPadDspVar = true
                UIView.animateWithDuration(1.0,
                    animations:
                    { self.view.frame.origin.y -= (self.KeyPadHytVal)},
                    completion: nil)
            }
            else
            {
                self.ChkKeyPadDspVar = false
            }
        }

    }

    func TdoWenKeyPadHyd(NfnPsgVar: NSNotification)
    {
        if (self.ChkKeyPadDspVar)
        {
            self.ChkKeyPadDspVar = false
            UIView.animateWithDuration(1.0,
                animations:
                { self.view.frame.origin.y += (self.KeyPadHytVal)},
                completion: nil)
        }
    }

    override func viewDidDisappear(animated: Bool)
    {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
        view.endEditing(true)
        ChkKeyPadDspVar = false
    }
}

| :: | ときどきビューが下がる場合、その場合は高さ+/- 150を使用します。

    NonKeyPadAraVar.size.height -= self.KeyPadHytVal + 150

    { self.view.frame.origin.y -= self.KeyPadHytVal  - 150},
                    completion: nil)

    { self.view.frame.origin.y += self.KeyPadHytVal  - 150},
                completion: nil)

0
func keyboardWillShow(notification: NSNotification) {

    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.view.frame.origin.y = self.view.frame.height - (self.view.frame.height + keyboardSize.height)
    }

}

func keyboardWillHide(notification: NSNotification) {
        self.view.frame.origin.y = 0
}

より安定している必要があります


0
 override func viewWillAppear(animated: Bool)
 {
 super.viewWillAppear(animated)

 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)

 }

 // MARK: - keyboard
 func keyboardWillShow(notification: NSNotification) 
{

if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: keyboardSize.height, right:contentInsets.right)
                    // ...
                } else {
                    // no UIKeyboardFrameBeginUserInfoKey entry in userInfo
                }
            } else {
                // no userInfo dictionary in notification
            }
        }

func keyboardWillHide(notification: NSNotification) 
{
let contentInsets = self.tblView.contentInset as UIEdgeInsets
self.tblView.contentInset = UIEdgeInsets(top: contentInsets.top, left: contentInsets.left, bottom: 0, right:contentInsets.right)
 }

0

次のコードを使用して、UITextField Clickedを表示します。

func textFieldDidBeginEditing(textField: UITextField) {
    ViewUpanimateMoving(true, upValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
    ViewUpanimateMoving(false, upValue: 100)
}
func ViewUpanimateMoving (up:Bool, upValue :CGFloat){
    var durationMovement:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -upValue : upValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(durationMovement)
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

0

私は問題を簡単にするためにココアポッドを作りました:

https://github.com/xtrinch/KeyboardLayoutHelper

どうやって使うのですか:

自動レイアウトの下部制約を作成し、それにKeyboardLayoutConstraintのクラスを与えますモジュールKeyboardLayoutHelperます。ポッドは、キーボードの表示と非表示に対応するためにそれを増やすために必要な作業を行います。使用例のプロジェクト例を参照してください(私は2つ作成しました:scrollView内のtextFieldsと、2つの基本的なビューを持つ垂直方向に中央揃えされたtextFields-ログインと登録)。

下部のレイアウト制約は、コンテナービュー、textField自体、任意の名前にすることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.