キーボードがすばやく表示されたときにテキストフィールドを移動する


217

iOSでのプログラミングにSwiftを使用しており、このコードを使用してを移動してUITextFieldいますが、機能しません。関数をkeyboardWillShow正しく呼び出しましたが、テキストフィールドが移動しません。自動レイアウトを使用しています。

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

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self);
}

func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        //let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)

        var frame = self.ChatField.frame
        frame.origin.y = frame.origin.y - keyboardSize.height + 167
        self.chatField.frame = frame
        println("asdasd")
    }
}

2
:プロジェクトファイルとチュートリアルガイドcodebeaulieu.com/43/...
ダン・ボーリュー

おそらくdeinitとviewDidLoadはバランスが取れていません。
Ricardo

Appleのドキュメントと個人的な経験の両方に基づいています。UIScrollViewを使用してTFを移動する私のgitレポは次のとおり
29satnam

回答:


315

既存の回答にはいくつかの改善点があります。

まず、UIKeyboardWillChangeFrameNotificationは、表示/非表示だけでなく、キーボードの変更(言語、サードパーティのキーボードの使用など)による回転や変更(ただし、キーボードが非表示になることを示す以下のコメントに注意)による変更を処理するため、おそらく最良の通知です。ハードウェアキーボード接続をサポートするためにも処理されます)。

次に、アニメーションパラメータを通知からプルして、アニメーションが適切に組み合わされていることを確認できます。

特に、ディクショナリコードを強制的にアンラップすることに慣れている場合は、このコードをもう少しクリーンアップするオプションがおそらくあります。

スウィフト3

class MyViewController: UIViewController {

// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    // Note that SO highlighting makes the new selector syntax (#selector()) look
    // like a comment but it isn't one
    NotificationCenter.default.addObserver(self,
        selector: #selector(self.keyboardNotification(notification:)),
        name: NSNotification.Name.UIKeyboardWillChangeFrame,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIViewAnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            self.keyboardHeightLayoutConstraint?.constant = 0.0
        } else {
            self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
        }
        UIView.animate(withDuration: duration,
                                   delay: TimeInterval(0),
                                   options: animationCurve,
                                   animations: { self.view.layoutIfNeeded() },
                                   completion: nil)
    }
}

(@Gaboxの以下の素晴らしいコメントに従って、縮小ではなくオフスクリーンでアニメーションするキーボードを考慮して編集されました)

スウィフト5

class MyViewController: UIViewController {

// This constraint ties an element at zero points from the bottom layout guide
@IBOutlet var keyboardHeightLayoutConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    // Note that SO highlighting makes the new selector syntax (#selector()) look
    // like a comment but it isn't one
    NotificationCenter.default.addObserver(self,
        selector: #selector(self.keyboardNotification(notification:)),
        name: UIResponder.keyboardWillChangeFrameNotification,
        object: nil)
}

deinit {
    NotificationCenter.default.removeObserver(self)
}

@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        let endFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
        let endFrameY = endFrame?.origin.y ?? 0
        let duration:TimeInterval = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if endFrameY >= UIScreen.main.bounds.size.height {
            self.keyboardHeightLayoutConstraint?.constant = 0.0
        } else {
            self.keyboardHeightLayoutConstraint?.constant = endFrame?.size.height ?? 0.0
        }
        UIView.animate(withDuration: duration,
                                   delay: TimeInterval(0),
                                   options: animationCurve,
                                   animations: { self.view.layoutIfNeeded() },
                                   completion: nil)
    }
}

1
@JosephLordいいね。しかし、endFrame?.size.heightnilではないため、キーボードが非表示の場合、これは機能しません。終了フレームはとして取得しましたUIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 1024}, {768, 264}}";。iOS 8.3 iPad Simulator、Portraitで実行。Xcode6.3 beta4。
Hlung、2015年

8
キーボードが非表示にならない場合は、このコードを使用してみてください。endFrame?.origin.y> = UIScreen.mainScreen()。bounds.size.height {self.keyboardHeightLayoutConstraint?.constant = 0.0} else {self.keyboardHeightLayoutConstraint?.constant = endFrame.size.height}
ガブリエルゴン

3
keyBoardHeightLayoutConstraintは、InterfaceBuilderで定義された制約で、ビューコントローラーの下部レイアウトガイドまたはメインビューの下部に移動/縮小するビューの下部を制限します。この定数は最初はゼロに設定されており、キーボードが表示されたりサイズが変更されたりしたときにキーボードのスペースを確保するために調整されます。
ジョセフ卿

2
.UIKeyboardWillChangeFrameiOSキーボードが消えたとしても、ハードウェアキーボードが接続されている場合は起動しません。あなた.UIKeyboardWillHideもそのエッジケースを捕らえるために観察する必要があります。
jamesk 2017

1
@Sulthanは大丈夫です。私の問題は、キーボードより少し高くなっています。これを修正する方法はありますか?
パブロス2017年

128

自動レイアウトを使用している場合は、下部スペースをスーパービュー制約に設定していると思います。その場合は、制約の値を更新するだけです。ここでは、少しアニメーションを使用してそれを行う方法を示します。

func keyboardWasShown(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

    UIView.animateWithDuration(0.1, animations: { () -> Void in
        self.bottomConstraint.constant = keyboardFrame.size.height + 20
    })
}

ハードコードされた20は、キーボードのテキストフィールドを少しだけポップするために追加されています。そうしないと、キーボードの上マージンとテキストフィールドの下マージンが接触します。

キーボードが閉じられたら、制約の値を元の値にリセットします。


1
それをどのように定義するかを説明していただけますか?ありがとう!私は常にストーリーボードですべてを制御します
ペドロマンフレディ2014

4
bottomConstraintは、コンストレイントに付けた名前です。私は定数を選択し、それにドラッグしてIBOutletを作成し、その名前を付けました。ボタンやテキストフィールドなどの他のUI要素と同じように、IBOutletsを制約に作成できます。
Isuru

2
この答えはうまくいきましたが、アニメーションがすぐに起こりました。チェック私は、制約の変更をアニメーション化するにはどうすればよいですか?適切にアニメーション化する方法について。
アダムジョンズ

2
@ vinbhai4u UIKeyboardWillShowNotification通知を登録する必要があります。OPの質問のコードを見てください。
Isuru

8
@AdamJohns制約の変更をアニメーション化するには、外部の定数を更新してanimateWithDuration呼び出しますself.view.layoutIfNeeded()、animateブロック内ます。
最大

110

簡単な解決策は、キーボードの高さを一定にしてビューを上に移動することです。

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

@objc func keyboardWillShow(sender: NSNotification) {
     self.view.frame.origin.y = -150 // Move view 150 points upward 
}

@objc func keyboardWillHide(sender: NSNotification) {
     self.view.frame.origin.y = 0 // Move view to original position  
}

スウィフト5:

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(sender:)), name: UIResponder.keyboardWillShowNotification, object: nil);

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

4
私はこの簡単な解決策が好きです。しかし、テキストフィールドを1つ以上移動したので、keyboardShowingブール値を追加しました。キーボードが表示されている間は、キーボードを1回だけ移動します。ありがとう。
ケン

2
ビューを移動する代わりに、textViewを移動します
ericgu

1
これにより、ユーザーが入力言語を切り替えた場合、ビューのy値がマイナスされたままになります。
Jeffrey Neo

self.viewを変更する代わりに、私はself.myConstraint値を変更しましたが、機能しますが、(制約が適用されている)ビューが上に移動し続けていることが重要です。誰かがこの問題に直面しましたか?
刺し

5
代わりに使用してのself.view.frame.origin.y -= 150使用をself.view.frame.origin.y = -150し、代わりにself.view.frame.origin.y += 150使用self.view.frame.origin.y = 0。これにより、新しいフィールドがタッチされるたびにビューが150移動するのを防ぎます。
gunwin 2016

43

テキストフィールドの編集中にビューを移動するには、これを試してください、私はこれを適用しました、

オプション1:-** ** Swift 5.0およびiPhone X、XR、XS、XSでの更新、 NotificationCenterを使用した最大移動

  • この通知をに登録 func viewWillAppear(_ animated: Bool)

  • この通知の登録を解除 func viewWillDisappear(_ animated: Bool)

注:-登録を解除しないと、子クラスから呼び出され、クラッシュまたはその他の理由になります。

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow(notification:)), name:  UIResponder.keyboardWillShowNotification, object: nil )
}
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc func keyboardWillShow( notification: Notification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        var newHeight: CGFloat
        let duration:TimeInterval = (notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve:UIView.AnimationOptions = UIView.AnimationOptions(rawValue: animationCurveRaw)
        if #available(iOS 11.0, *) {
            newHeight = keyboardFrame.cgRectValue.height - self.view.safeAreaInsets.bottom
        } else {
            newHeight = keyboardFrame.cgRectValue.height
        }
        let keyboardHeight = newHeight  + 10 // **10 is bottom margin of View**  and **this newHeight will be keyboard height**
        UIView.animate(withDuration: duration,
                       delay: TimeInterval(0),
                       options: animationCurve,
                       animations: {
                        self.view.textViewBottomConstraint.constant = keyboardHeight **//Here you can manage your view constraints for animated show**
                        self.view.layoutIfNeeded() },
                       completion: nil)
    }
}

オプション2:- 正常に機能

func textFieldDidBeginEditing(textField: UITextField) {
        self.animateViewMoving(up: true, moveValue: 100)
}
func textFieldDidEndEditing(textField: UITextField) {
        self.animateViewMoving(up: false, moveValue: 100)
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
    var movementDuration:NSTimeInterval = 0.3
    var movement:CGFloat = ( up ? -moveValue : moveValue)
    UIView.beginAnimations( "animateView", context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(movementDuration )
    self.view.frame = CGRectOffset(self.view.frame, 0,  movement)
    UIView.commitAnimations()
}

キーボードがSwiftに表示されたときに、このソースUITextFieldが上に移動して、この回答を得ました

IN Swift 4 ---

func textFieldDidBeginEditing(_ textField: UITextField) {
        animateViewMoving(up: true, moveValue: 100)
    }

    func textFieldDidEndEditing(_ textField: UITextField) {
        animateViewMoving(up: false, moveValue: 100)
    }
    func animateViewMoving (up:Bool, moveValue :CGFloat){
        let movementDuration:TimeInterval = 0.3
        let movement:CGFloat = ( up ? -moveValue : moveValue)
        UIView.beginAnimations( "animateView", context: nil)
        UIView.setAnimationBeginsFromCurrentState(true)
        UIView.setAnimationDuration(movementDuration ) 
        self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
        UIView.commitAnimations()
    }

1
@ Jogendra.Com、ご苦労様でした。しかし、iPhone 5、4s、6で最適に動作します。しかし、iPhone 6plusとiPad(上位のもの)で無効にするにはどうすればよいですか
Thiha Aung

オプション1を使用している場合は、必ず制約IBOutletを追加してください。Auto-layoutを使用してサイズを変更する制約を作成し、それをビューコントローラーにドラッグアンドドロップして、アニメーション関数でself.iboutletConstraint.constantとして参照するIBOutletを作成します。また、これはキーボードを非表示にしてもアウトレットを再調整しません。制約を元の値にリセットすることで処理しました。
Hammad Tariq

21

きれいなSwiftコードが大好きです。キーボードでテキストビューを上下に移動するために思いつくコードは次のとおりです。現在、iOS8 / 9 Swift 2本番アプリで動作しています。

更新(2016年3月):以前のコードをできるだけ厳しくしました。また、キーボードの高さとアニメーションパラメータをハードコーディングする人気のある答えがたくさんあります。これらの回答の数値は、6s以上のiOS9に表示される実際の値(キーボードの高さ226、継続時間0.25、アニメーションカーブ7)と常に一致するとは限らないことは言うまでもありません。いずれにせよ、これらの値をシステムから直接取得するための追加のコードはほとんどありません。下記参照。

override func viewDidLoad() {
    super.viewDidLoad()

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

func animateWithKeyboard(notification: NSNotification) {

    // Based on both Apple's docs and personal experience, 
    // I assume userInfo and its documented keys are available.
    // If you'd like, you can remove the forced unwrapping and add your own default values.

    let userInfo = notification.userInfo!
    let keyboardHeight = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().height
    let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double
    let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt
    let moveUp = (notification.name == UIKeyboardWillShowNotification)

    // baseContraint is your Auto Layout constraint that pins the
    // text view to the bottom of the superview.

    baseConstraint.constant = moveUp ? -keyboardHeight : 0

    let options = UIViewAnimationOptions(rawValue: curve << 16)
    UIView.animateWithDuration(duration, delay: 0, options: options,
        animations: {
            self.view.layoutIfNeeded()
        },
        completion: nil
    )

}

注:このコードは、ほとんどのコメント/一般的なケースをカバーしています。ただし、さまざまな方向やカスタムキーボードを処理するには、さらにコードが必要になる場合があります。iOSキーボードの操作に関する詳細な記事を次に示します。すべてのシナリオを処理する必要がある場合は、これが役立つことがあります。


Swift 1.1のようですがas、強制キャストに使用するため、Swift 1.2でコンパイルできないと思います。as!うまくいくかもしれませんが、このページの他の場所でわかるように、私はフォースキャストを避け、強制的にアンラップします。
ジョセフ卿

現在Swift 1.2でコンパイルされています。そして、コードre:強制アンラップにコメントを追加しました。乾杯。
scootermg 2016

おっとっと。私はSwift 2を意味していました
scootermg 2016

リンク方法によってbaseConstraintは、のbaseConstraint.constant = moveUp ? keyboardHeight : 0代わりになる場合がありますbaseConstraint.constant = moveUp ? -keyboardHeight : 0
limfinity

15

編集:より簡単でクリーンなソリューションをお勧めします。下部の間隔制約のクラスをKeyboardLayoutConstraintに変更するだけです。自動的にキーボードの高さに拡大します。


これは@JosephLordの回答の改良版です。

iOS 8.3 iPad Simulator、Portraitでテストされています。Xcode6.3 beta4、が原因でキーボードが非表示になっているUIKeyboardFrameEndUserInfoKeyと、彼の回答が機能しません"NSRect: {{0, 1024}, {768, 264}}";。高さは決してありません0

これは、伝統的に使用するために戻ってUIKeyboardWillShowNotificationUIKeyboardWillHideNotificationキーボードが終了フレームの高さに頼るのではなく、隠れているときよりよく伝えるために。UIKeyboardWillShowNotificationキーボードフレームが変更されたときにも送信されるため、すべての使用例をカバーする必要があります。

    // You have to set this up in storyboard first!. 
    // It's a vertical spacing constraint between view and bottom of superview.
    @IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillShowNotification, object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardNotification:"), name:UIKeyboardWillHideNotification, object: nil);
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    func keyboardNotification(notification: NSNotification) {

        let isShowing = notification.name == UIKeyboardWillShowNotification

        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let endFrameHeight = endFrame?.size.height ?? 0.0
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.bottomSpacingConstraint?.constant = isShowing ? endFrameHeight : 0.0
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
    }

編集内容を説明していただけますか?うまくいきませんでした。下部にボタンがあるUIScrollViewがあります。下部のマージン下部制約にクラスを設定しました。
schw4ndi 2017

@ schw4ndiあなたの下部の制約はどのビューに関連付けられていますか?スクロールビューの下部をそのスクロールビューのスーパービューの下部に接続する必要があります。
Hlung 2017

ああありがとう、ボタンとscrollViewの間に制約がありました
schw4ndi

9

私はSwift 4を使用していますが、余分な下部制約を使用せずにこの問題を解決しています。コードはこちらにあります。

1)ロードされた通知オブザーバーを追加

override func viewDidLoad() {
        super.viewDidLoad()
        setupManager()
        // Do any additional setup after loading the view.
        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)
    }

2)通知オブザーバーを削除します

deinit {
        NotificationCenter.default.removeObserver(self)
    }

3)次のようなキーボードの表示/非表示メソッドを追加します

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

@objc func keyboardWillHide(notification: NSNotification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            UIView.animate(withDuration: 0.1, animations: { () -> Void in
                self.view.frame.origin.y += keyboardSize.height
                self.view.layoutIfNeeded()
            })
        }
    }

4)textfeildデリゲートを追加し、touchesBeganメソッド.usefullを追加して、画面上のtextfeildの外側をタッチしたときにキーボードを非表示にします

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

    }

する必要がありますUIKeyboardFrameEndUserInfoKey
マイクロ

1
NSNotification.Name.UIKeyboardWillShow UIResponder.keyboardWillShowNotificationも次の UIKeyboardFrameBeginUserInfoKey ように 名前が変更されますUIResponder.keyboardFrameBeginUserInfoKey
smj

7

これは、@ JosephLordと@Hlungの回答の改良版です。タブバーの有無にかかわらず適用できます。また、キーボードで移動したビューを元の位置に完全に復元します。

// You have to set this up in storyboard first!. 
// It's a vertical spacing constraint between view and bottom of superview.
@IBOutlet weak var bottomSpacingConstraint: NSLayoutConstraint! 

override func viewDidLoad() {
        super.viewDidLoad()            

        //    Receive(Get) Notification
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardNotification:", name: UIKeyboardWillHideNotification, object: nil)


        self.originalConstraint = self.keyboardHeightLayoutConstraint?.constant //for original coordinate.
}

func keyboardNotification(notification: NSNotification) {
        let isShowing = notification.name == UIKeyboardWillShowNotification

        var tabbarHeight: CGFloat = 0
        if self.tabBarController? != nil {
            tabbarHeight = self.tabBarController!.tabBar.frame.height
        }
        if let userInfo = notification.userInfo {
            let endFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
            let duration:NSTimeInterval = (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
            let animationCurveRawNSN = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber
            let animationCurveRaw = animationCurveRawNSN?.unsignedLongValue ?? UIViewAnimationOptions.CurveEaseInOut.rawValue
            let animationCurve:UIViewAnimationOptions = UIViewAnimationOptions(rawValue: animationCurveRaw)
            self.keyboardHeightLayoutConstraint?.constant = isShowing ? (endFrame!.size.height - tabbarHeight) : self.originalConstraint!
            UIView.animateWithDuration(duration,
                delay: NSTimeInterval(0),
                options: animationCurve,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }
}

6

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

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

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


2
素晴らしい解決策!ただし、制約の最初の項目としてSafe Area.Bottomが必要です(2番目の項目の場合は機能しませんでした)。また、定数を0に設定すると、フィールドとキーボードを表示するのに十分なだけ移動するのではなく、定数を保存して調整するため、最適に機能しました。
ミスランディア2018年

KeyboardLayoutConstraint swift4バージョンはありますか?
jeet.chanchawat

6

キーボードの表示/非表示を処理するSwift 3プロトコルを作成しました

import UIKit

protocol KeyboardHandler: class {

var bottomConstraint: NSLayoutConstraint! { get set }

    func keyboardWillShow(_ notification: Notification)
    func keyboardWillHide(_ notification: Notification)
    func startObservingKeyboardChanges()
    func stopObservingKeyboardChanges()
}


extension KeyboardHandler where Self: UIViewController {

    func startObservingKeyboardChanges() {

        // NotificationCenter observers
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillShow, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with rotations
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        // Deal with keyboard change (emoji, numerical, etc.)
        NotificationCenter.default.addObserver(forName: NSNotification.Name.UITextInputCurrentInputModeDidChange, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillShow(notification)
        }

        NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillHide, object: nil, queue: nil) { [weak self] notification in
          self?.keyboardWillHide(notification)
        }
    }


    func keyboardWillShow(_ notification: Notification) {

      let verticalPadding: CGFloat = 20 // Padding between the bottom of the view and the top of the keyboard

      guard let value = notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
      let keyboardHeight = value.cgRectValue.height

      // Here you could have more complex rules, like checking if the textField currently selected is actually covered by the keyboard, but that's out of this scope.
      self.bottomConstraint.constant = keyboardHeight + verticalPadding

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func keyboardWillHide(_ notification: Notification) {
      self.bottomConstraint.constant = 0

      UIView.animate(withDuration: 0.1, animations: { () -> Void in
          self.view.layoutIfNeeded()
      })
  }


  func stopObservingKeyboardChanges() {
      NotificationCenter.default.removeObserver(self)
  }

}

次に、それをUIViewControllerに実装するには、次のようにします。

  • viewControllerをこのプロトコルに準拠させます。

    class FormMailVC: UIViewControlle, KeyboardHandler {
  • viewWillAppearでキーボードの変更の監視を開始します。

    // MARK: - View controller life cycle
    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      startObservingKeyboardChanges()
    }
  • viewWillDisappearでのキーボードの変更の監視を停止します。

    override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      stopObservingKeyboardChanges()
    }
  • ストーリーボードから下部制約のIBOutletを作成します。

    // NSLayoutConstraints
    @IBOutlet weak var bottomConstraint: NSLayoutConstraint!

    (すべてのUIを「contentView」内に埋め込み、このプロパティにこのcontentViewから下部のレイアウトガイドへの下部制約をリンクすることをお勧めします) コンテンツビューの下部の制約

  • 最上位の制約の優先度を250(低)に変更します

コンテンツビューの上部の制約

これは、キーボードが表示されたときにコンテンツビュー全体を上にスライドさせるためです。優先順位は、コンテンツハグの優先順位/コンテンツの圧縮耐性の優先順位など、サブビューの他の制約の優先順位よりも低くする必要があります。

  • Autolayoutに、contentViewを上にスライドする方法を決定するための十分な制約があることを確認してください。

これには、「等しい」制約を追加する必要がある場合があります。 「より大きい」制約

そして、ここに行きます! キーボードなし

キーボード付き


警告なしで「Relation = Equal」を指定しても機能します。
Valtoni Boaventura 2017

平等な関係を置くと、特定の状況でのみ機能する場合があります。また、自動レイアウトの不整合に関する警告が表示される場合もあります。それはあなた自身のレイアウトに依存します。そういうわけで私は「あなたがしなければならないかもしれない」と言った。
フレデリック・ダッダ

OKフレデリック、同意した。素晴らしい解決策でした!
Valtoni Boaventura 2017

行方不明import UIKit
ミルコ

6

そのような単純なUIViewController 拡張を使用できます

//MARK: - Observers
extension UIViewController {

    func addObserverForNotification(notificationName: String, actionBlock: (NSNotification) -> Void) {
        NSNotificationCenter.defaultCenter().addObserverForName(notificationName, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: actionBlock)
    }

    func removeObserver(observer: AnyObject, notificationName: String) {
        NSNotificationCenter.defaultCenter().removeObserver(observer, name: notificationName, object: nil)
    }
}

//MARK: - Keyboard observers
extension UIViewController {

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
        willHide willHideClosure: KeyboardHeightClosure?) {
            NSNotificationCenter.defaultCenter().addObserverForName(UIKeyboardWillChangeFrameNotification,
                object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: { [weak self](notification) in
                    if let userInfo = notification.userInfo,
                        let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue(),
                        let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                        let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                        let kFrame = self?.view.convertRect(frame, fromView: nil),
                        let kBounds = self?.view.bounds {

                            let animationType = UIViewAnimationOptions(rawValue: c)
                            let kHeight = kFrame.size.height
                            UIView.animateWithDuration(duration, delay: 0, options: animationType, animations: {
                                if CGRectIntersectsRect(kBounds, kFrame) { // keyboard will be shown
                                    willShowClosure?(kHeight)
                                } else { // keyboard will be hidden
                                    willHideClosure?(kHeight)
                                }
                                }, completion: nil)
                    } else {
                            print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                    }
            })
    }

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIKeyboardWillChangeFrameNotification)
    }
}

使用例

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

        removeKeyboardObserver()
    }

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

    addKeyboardChangeFrameObserver(willShow: { [weak self](height) in
        //Update constraints here
        self?.view.setNeedsUpdateConstraints()
        }, willHide: { [weak self](height) in
        //Reset constraints here
        self?.view.setNeedsUpdateConstraints()
    })
}

Swift 4ソリューション

//MARK: - Observers
extension UIViewController {

  func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
    NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
  }

  func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
    NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
  }
}

//MARK: - Keyboard handling
extension UIViewController {

  typealias KeyboardHeightClosure = (CGFloat) -> ()

  func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
                                      willHide willHideClosure: KeyboardHeightClosure?) {
    NotificationCenter.default.addObserver(forName: NSNotification.Name.UIKeyboardWillChangeFrame,
                                           object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
                                            if let userInfo = notification.userInfo,
                                              let frame = (userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
                                              let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double,
                                              let c = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt,
                                              let kFrame = self?.view.convert(frame, from: nil),
                                              let kBounds = self?.view.bounds {

                                              let animationType = UIViewAnimationOptions(rawValue: c)
                                              let kHeight = kFrame.size.height
                                              UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
                                                if kBounds.intersects(kFrame) { // keyboard will be shown
                                                  willShowClosure?(kHeight)
                                                } else { // keyboard will be hidden
                                                  willHideClosure?(kHeight)
                                                }
                                              }, completion: nil)
                                            } else {
                                              print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                                            }
    })
  }

  func removeKeyboardObserver() {
    removeObserver(self, notificationName: NSNotification.Name.UIKeyboardWillChangeFrame)
  }
}

Swift 4.2

//MARK: - Keyboard handling
extension UIViewController {

    func addObserverForNotification(_ notificationName: Notification.Name, actionBlock: @escaping (Notification) -> Void) {
        NotificationCenter.default.addObserver(forName: notificationName, object: nil, queue: OperationQueue.main, using: actionBlock)
    }

    func removeObserver(_ observer: AnyObject, notificationName: Notification.Name) {
        NotificationCenter.default.removeObserver(observer, name: notificationName, object: nil)
    }

    typealias KeyboardHeightClosure = (CGFloat) -> ()

    func removeKeyboardObserver() {
        removeObserver(self, notificationName: UIResponder.keyboardWillChangeFrameNotification)
    }

    func addKeyboardChangeFrameObserver(willShow willShowClosure: KeyboardHeightClosure?,
                                        willHide willHideClosure: KeyboardHeightClosure?) {
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification,
                                               object: nil, queue: OperationQueue.main, using: { [weak self](notification) in
                                                if let userInfo = notification.userInfo,
                                                    let frame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
                                                    let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double,
                                                    let c = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt,
                                                    let kFrame = self?.view.convert(frame, from: nil),
                                                    let kBounds = self?.view.bounds {

                                                    let animationType = UIView.AnimationOptions(rawValue: c)
                                                    let kHeight = kFrame.size.height
                                                    UIView.animate(withDuration: duration, delay: 0, options: animationType, animations: {
                                                        if kBounds.intersects(kFrame) { // keyboard will be shown
                                                            willShowClosure?(kHeight)
                                                        } else { // keyboard will be hidden
                                                            willHideClosure?(kHeight)
                                                        }
                                                    }, completion: nil)
                                                } else {
                                                    print("Invalid conditions for UIKeyboardWillChangeFrameNotification")
                                                }
        })
    }
}

2
他のソリューションよりもはるかに「速い」/すべてのコントローラーを書き換えなくても優れた/再利用可能->間違いなくここで最高のもの:)
Tib

私は試しましたが、チャンスはありません、UIScrollViewが必要ですか?
erdemgc

@erdemgc使用例を見ましたか?必要なのは、UIViewControlller + addKeyboardChangeFrameObserverだけです。削除することを忘れないでください
ale_stro

removeKeyboardObserver()ここのメソッドは実際にはオブザーバーを削除しません。これを呼び出さないとInvalid conditions for UIKeyboardWillChangeFrameNotification、コンソールにaddメソッドからが表示されます。これを呼び出すと、同じエラーが表示されます。つまり、オブザーバーは削除されません。ドキュメントには、「オブザベーションの登録を解除するには、このメソッドによって返されたオブジェクトをに渡す」と記載されていremoveObserver(_:)ます。したがって、代わりに、そのメソッドによって返されたオブジェクトを保存し、オブザーバーを削除するときにそれを渡します。
Huy-Anh Hoang

実際、scrollviewが読み込まれると、boundには値が割り当てられ、キーボードフレームがboundと交差する場合にキーボードが非表示になるかどうかを検出できません。
ジェームズ・キム

5

このライブラリを使用すると、appDidFinishedLaunchingとuで1行のコードが実行されます。

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

    IQKeyboardManager.sharedManager().enable = true
    return true
}

IQKeyboardManager-キーボードがリンクを表示するたびにビューを調整-https ://github.com/hackiftekhar/IQKeyboardManager


4
struct MoveKeyboard {
    static let KEYBOARD_ANIMATION_DURATION : CGFloat = 0.3
    static let MINIMUM_SCROLL_FRACTION : CGFloat = 0.2;
    static let MAXIMUM_SCROLL_FRACTION : CGFloat = 0.8;
    static let PORTRAIT_KEYBOARD_HEIGHT : CGFloat = 216;
    static let LANDSCAPE_KEYBOARD_HEIGHT : CGFloat = 162;
}


  func textFieldDidBeginEditing(textField: UITextField) {
    let textFieldRect : CGRect = self.view.window!.convertRect(textField.bounds, fromView: textField)
    let viewRect : CGRect = self.view.window!.convertRect(self.view.bounds, fromView: self.view)

    let midline : CGFloat = textFieldRect.origin.y + 0.5 * textFieldRect.size.height
    let numerator : CGFloat = midline - viewRect.origin.y - MoveKeyboard.MINIMUM_SCROLL_FRACTION * viewRect.size.height
    let denominator : CGFloat = (MoveKeyboard.MAXIMUM_SCROLL_FRACTION - MoveKeyboard.MINIMUM_SCROLL_FRACTION) * viewRect.size.height
    var heightFraction : CGFloat = numerator / denominator

    if heightFraction < 0.0 {
        heightFraction = 0.0
    } else if heightFraction > 1.0 {
        heightFraction = 1.0
    }

    let orientation : UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown) {
        animateDistance = floor(MoveKeyboard.PORTRAIT_KEYBOARD_HEIGHT * heightFraction)
    } else {
        animateDistance = floor(MoveKeyboard.LANDSCAPE_KEYBOARD_HEIGHT * heightFraction)
    }

    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y -= animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)
    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()
}


func textFieldDidEndEditing(textField: UITextField) {
    var viewFrame : CGRect = self.view.frame
    viewFrame.origin.y += animateDistance

    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationBeginsFromCurrentState(true)

    UIView.setAnimationDuration(NSTimeInterval(MoveKeyboard.KEYBOARD_ANIMATION_DURATION))

    self.view.frame = viewFrame

    UIView.commitAnimations()

}

最後に、デリゲートメソッドを使用しているため

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

Objective-Cの使用からリファクタリングされましたhttp://www.cocoawithlove.com/2008/10/sliding-uitextfields-around-to-avoid.html


このソリューションは私にとってはうまくいきましたが、いくつか追加の作業を行うvar animateDistance: CGFloat!必要がありました。ユーザーがキーボードの非表示ボタンを押したときにUIKeyboardWillHideNotificationを処理する必要があるプラスを宣言します。
Rhuantavan

4

自動レイアウト、制約、またはアウトレットに依存しない別のソリューション。必要なのは、スクロールビューのフィールドです。

override func viewDidLoad() {
    super.viewDidLoad()

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

func makeSpaceForKeyboard(notification: NSNotification) {
    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })
    } else {
        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }

}

1
UIKeyboardWillShowNotification呼び出された後、黒い画面が表示されます。
Sachin Kumaram

4

これがSwift 2.2のソリューションの私のバージョンです:

キーボードの表示/非表示通知の最初の登録

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

次に、それらの通知に対応するメソッドで、メインビューを上下に移動します

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

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

トリックは「keyboardWillShow」部分にあり、「QuickType提案バー」が展開または縮小されるたびに呼び出しを取得します。次に、メインビューのy座標を常に設定します。これは、キーボードの高さの合計の負の値に等しくなります(「QuickTypeバー」部分の有無にかかわらず)。

最後にオブザーバーを削除することを忘れないでください

deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}

3

以下は簡単な解決策です。テキストフィールドには、下部のレイアウトガイドに結び付ける制約があります。キーボードの高さを制約の定数に追加するだけです。

// This constraint ties the text field to the bottom layout guide
@IBOutlet var textFieldToBottomLayoutGuideConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    super.viewDidLoad()

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

func keyboardWillShow(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant += keyboardSize.height
    }
}

func keyboardWillHide(sender: NSNotification) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
        self.textFieldToBottomLayoutGuideConstraint?.constant -= keyboardSize.height
    }
}

3

まあ、私は手遅れかもしれないと思うが、私はSaqibの答えの別の簡単なバージョンを見つけた。制約付きのAutolayoutを使用しています。ユーザー名とパスワードのフィールドを持つ別のメインビューの中に小さなビューがあります。ビューのy座標を変更する代わりに、元の制約値を変数に保存し、制約の定数をある値に変更し、キーボードを閉じた後、元の制約に設定します。このようにして、Saqibの回答が抱える問題を回避します(ビューは上に移動し続け、停止しません)。以下は私のコードです...

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);
    self.originalConstraint = self.centerYConstraint.constant
  }

  func keyboardWillShow(sender: NSNotification) {
    self.centerYConstraint.constant += 30
  }

  func keyboardWillHide(sender: NSNotification) {
    self.centerYConstraint.constant = self.originalConstraint
  }

keyboardWillShowメソッドの内部で 、self.centerYConstraint.constant == self.originalCenterYConstraintの条件を確認し、この条件の間にコードを1行挿入します。OriginalCenterYContraintは、viewdidloadに格納しているcenterYContraintの元の値です。これでうまくいきました。
Sashi 2015

3

Swift 4.xの回答。@ Joseph Lordと@Isuruからの回答をマージします。bottomConstraint移動するビューの下部の制約を表します。

override func viewDidLoad() {
    // Call super
    super.viewDidLoad()

    // Subscribe to keyboard notifications
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(keyboardNotification(notification:)),
                                           name: UIResponder.keyboardWillChangeFrameNotification,
                                           object: nil)        
}


deinit {
    NotificationCenter.default.removeObserver(self)
}


@objc func keyboardNotification(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        // Get keyboard frame
        let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

        // Set new bottom constraint constant
        let bottomConstraintConstant = keyboardFrame.origin.y >= UIScreen.main.bounds.size.height ? 0.0 : keyboardFrame.size.height

        // Set animation properties
        let duration = (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0
        let animationCurveRawNSN = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber
        let animationCurveRaw = animationCurveRawNSN?.uintValue ?? UIView.AnimationOptions.curveEaseInOut.rawValue
        let animationCurve = UIView.AnimationOptions(rawValue: animationCurveRaw)

        // Animate the view you care about
        UIView.animate(withDuration: duration, delay: 0, options: animationCurve, animations: {
            self.bottomConstraint.constant = bottomConstraintConstant
            self.view.layoutIfNeeded()
        }, completion: nil)
    }
}

2

私は次の方法で行いました:

これは、テキストフィールドのスーパービューがビューの場合に役立ちます

class AdminLoginViewController: UIViewController,
UITextFieldDelegate{

    @IBOutlet weak var txtUserName: UITextField!
    @IBOutlet weak var txtUserPassword: UITextField!
    @IBOutlet weak var btnAdminLogin: UIButton!

    private var activeField : UIView?

    var param:String!
    var adminUser : Admin? = nil
    var kbHeight: CGFloat!

    override func viewDidLoad()
    {
        self.addKeyBoardObserver()
        self.addGestureForHideKeyBoard()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func addGestureForHideKeyBoard()
    {
        let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard"))
        tapGesture.cancelsTouchesInView = false
        view.addGestureRecognizer(tapGesture)
    }

    func hideKeyboard() {
        self.view.endEditing(true)
    }

    func addKeyBoardObserver(){

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

    func removeObserver(){
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    //MARK:- textfiled Delegate

    func textFieldShouldBeginEditing(textField: UITextField) -> Bool
    {
         activeField = textField

        return true
    }
    func textFieldShouldEndEditing(textField: UITextField) -> Bool
    {
        if activeField == textField
        {
            activeField = nil
        }

        return true
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {

        if txtUserName == textField
        {
            txtUserPassword.becomeFirstResponder()
        }
        else if (textField == txtUserPassword)
        {
            self.btnAdminLoginAction(nil)
        }
        return true;
    }

    func willChangeKeyboardFrame(aNotification : NSNotification)
    {
       if self.activeField != nil && self.activeField!.isFirstResponder()
    {
        if let keyboardSize =  (aNotification.userInfo![UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue()
        {
            let dy = (self.activeField?.superview?.convertRect((self.activeField?.frame)!, toView: view).origin.y)!

            let height = (self.view.frame.size.height - keyboardSize.size.height)

            if dy > height
            {
                var frame = self.view.frame

                frame.origin.y = -((dy - height) + (self.activeField?.frame.size.height)! + 20)

                self.view.frame = frame
            }
        }
    }
    else
    {
        var frame = self.view.frame
        frame.origin.y = 0
        self.view.frame = frame
    }
    } }

2
    func registerForKeyboardNotifications(){
        //Keyboard
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWasShown), name: UIKeyboardDidShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(keyboardWillBeHidden), name: UIKeyboardDidHideNotification, object: nil)


    }
    func deregisterFromKeyboardNotifications(){

        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)

    }
    func keyboardWasShown(notification: NSNotification){

        let userInfo: NSDictionary = notification.userInfo!
        let keyboardInfoFrame = userInfo.objectForKey(UIKeyboardFrameEndUserInfoKey)?.CGRectValue()

        let windowFrame:CGRect = (UIApplication.sharedApplication().keyWindow!.convertRect(self.view.frame, fromView:self.view))

        let keyboardFrame = CGRectIntersection(windowFrame, keyboardInfoFrame!)

        let coveredFrame = UIApplication.sharedApplication().keyWindow!.convertRect(keyboardFrame, toView:self.view)

        let contentInsets = UIEdgeInsetsMake(0, 0, (coveredFrame.size.height), 0.0)
        self.scrollViewInAddCase .contentInset = contentInsets;
        self.scrollViewInAddCase.scrollIndicatorInsets = contentInsets;
        self.scrollViewInAddCase.contentSize = CGSizeMake((self.scrollViewInAddCase.contentSize.width), (self.scrollViewInAddCase.contentSize.height))

    }
    /**
     this method will fire when keyboard was hidden

     - parameter notification: contains keyboard details
     */
    func keyboardWillBeHidden (notification: NSNotification) {

        self.scrollViewInAddCase.contentInset = UIEdgeInsetsZero
        self.scrollViewInAddCase.scrollIndicatorInsets = UIEdgeInsetsZero

    }

1
上記のコードを使用して、テキストフィールドをキーボードの上に移動します。Swift2.2では問題なく動作します。私はそれが誰かを助けることを願っています。
Kamalkumar.E 2016

1

私は次の方法で行いました:

class SignInController: UIViewController , UITextFieldDelegate {

@IBOutlet weak var scrollView: UIScrollView!

// outlet declartion
@IBOutlet weak var signInTextView: UITextField!

var kbHeight: CGFloat!

/**
*
* @method viewDidLoad
*
*/

override func viewDidLoad() {
    super.viewDidLoad()

    self.signInTextView.delegate = self

}// end viewDidLoad

/**
*
* @method viewWillAppear
*
*/

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

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

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

}// end viewWillAppear

/**
*
* @method viewDidAppear
*
*/

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)


}// end viewDidAppear

/**
*
* @method viewWillDisappear
*
*/
override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

/**
*
* @method textFieldShouldReturn
* retun the keyboard value
*
*/

// MARK -
func textFieldShouldReturn(textField: UITextField) -> Bool {
    signInTextView.resignFirstResponder()
    return true;

}// end textFieldShouldReturn

// MARK - keyboardWillShow
func keyboardWillShow(notification: NSNotification) {
    if let userInfo = notification.userInfo {
        if let keyboardSize =  (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
            kbHeight = keyboardSize.height
            self.animateTextField(true)
        }
    }
}// end keyboardWillShow

// MARK - keyboardWillHide
func keyboardWillHide(notification: NSNotification) {
    self.animateTextField(false)
}// end keyboardWillHide

// MARK - animateTextField
func animateTextField(up: Bool) {
    var movement = (up ? -kbHeight : kbHeight)

    UIView.animateWithDuration(0.3, animations: {
        self.view.frame = CGRectOffset(self.view.frame, 0, movement)
    })
}// end animateTextField

/**
*
* @method didReceiveMemoryWarning
*
*/

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.

}// end didReceiveMemoryWarning


}// end SignInController

1

上記のすべての解決策を試しても私の問題が解決されない私のような場合、私はあなたに魅力のように機能する素晴らしい解決策を手に入れました。最初に、上記のソリューションのいくつかについていくつか説明します。

  1. 私の場合、要素に自動レイアウトが適用されていない場合にのみIQkeyboardmanagerが機能していました。それが適用された場合、IQkeyboard Managerは私たちの考えたとおりに機能しません。
  2. self.viewが上方向に移動した場合も同様です。
  3. ユーザーがクリックしたときにUITexfieldを上方にプッシュする迅速なサポートを備えた目的のcヘッダーを記述し、UITextfieldをカバーするキーボードの問題を解決しました:https : //github.com/coolvasanth/smart_keyboard
  4. iOSアプリ開発で中級以上のレベルを持っている人は、リポジトリを簡単に理解して実装できます。ではごきげんよう

1

すべてのTextFieldステップの一般的なソリューションは次のとおりです-

1)他のViewControllerによって拡張される共通のViewControllerを作成します

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.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        if self.view.frame.origin.y == 0 {
            self.view.frame.origin.y -= getMoveableDistance(keyboarHeight: keyboardSize.height)
        }
    }
}

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

//get the distance to move up the main view for the focus textfiled
func getMoveableDistance(keyboarHeight : CGFloat) ->  CGFloat{
    var y:CGFloat = 0.0
    if let activeTF = getSelectedTextField(){
        var tfMaxY = activeTF.frame.maxY
        var containerView = activeTF.superview!
        while containerView.frame.maxY != self.view.frame.maxY{
            let contViewFrm = containerView.convert(activeTF.frame, to: containerView.superview)
            tfMaxY = tfMaxY + contViewFrm.minY
            containerView = containerView.superview!
        }
        let keyboardMinY = self.view.frame.height - keyboarHeight
        if tfMaxY > keyboardMinY{
            y = (tfMaxY - keyboardMinY) + 10.0
        }
    }

    return y
}

2)UIViewControllerの拡張と現在アクティブなTextFieldを作成します

//get active text field

拡張UIViewController {func getSelectedTextField()-> UITextField?{

    let totalTextFields = getTextFieldsInView(view: self.view)

    for textField in totalTextFields{
        if textField.isFirstResponder{
            return textField
        }
    }

    return nil

}

func getTextFieldsInView(view: UIView) -> [UITextField] {

    var totalTextFields = [UITextField]()

    for subview in view.subviews as [UIView] {
        if let textField = subview as? UITextField {
            totalTextFields += [textField]
        } else {
            totalTextFields += getTextFieldsInView(view: subview)
        }
    }

    return totalTextFields
}

}


何らかの理由で、keyboardWillShow関数で問題が発生しました。最初のキーボードの切り替え後、keyboardSizeのサイズが間違っていました(最初の切り替えには正しいフレームがあります)。これを修正して、guard let userInfo = notification.userInfo else {return} guard let keyboardSize = userInfo [UIResponder.keyboardFrameEndUserInfoKey]に変更しました。NSValue else {return} let keyboardFrame = keyboardSize.cgRectValue if self.view.frame.origin.y == 0 {self.view.frame.origin.y-= getMoveableDistance(keyboarHeight:keyboardFrame.height)}。誰かが同じ問題を抱えていた場合:)
Youstanzr

1

非常にシンプルで、これ以上コーディングする必要はありません。ただ、追加pod 'IQKeyboardManagerSwift'あなたのpodfileで、そして自分の中でAppDelegate以下のページを追加コード。

import IQKeyboardManagerSwift

そしてメソッドdidFinishLaunchingWithOptions()タイプ

IQKeyboardManager.shared.enable = true

それだ。より良く理解するために、このビデオのリンクをチェックhttps://youtu.be/eOM94K1ZWN8 これはあなたを助けることを願っています。


TextViewで動作しますか?また、リターンキー「Done」のタイトルを変更するにはどうすればよいですか?
tdt kien

Goto:-"IQKeyboardManager.m"この行を置き換えます(行番号968):-[textField addDoneOnKeyboardWithTarget:self action:@selector(doneAction :) shouldShowPlaceholder:_shouldShowTextFieldPlaceholder] with this:-[textField addRightButtonOnKeyboardWithText:@ "YOURTEXT" target:セルフアクション:@selector(doneAction :) shouldShowPlaceholder:_shouldShowTextFieldPlaceholder]; そして、textviewをまだ試していません。これが役立つことを願っています。
Raghib Arshi

1

キーボードを管理するための完全なコード。

        override func viewWillAppear(_ animated: Bool) {
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(StoryMediaVC.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        override func viewWillDisappear(_ animated: Bool) {
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
            NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        @objc func keyboardWillShow(notification: NSNotification) {
            guard let userInfo = notification.userInfo else {return}
            guard let keyboardSize = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else {return}
            let keyboardFrame = keyboardSize.cgRectValue

            if self.view.bounds.origin.y == 0{
                self.view.bounds.origin.y += keyboardFrame.height
            }
        }


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

0

@Simpaソリューションを少し変更しました......

override func viewDidLoad() 
{

    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillShowNotification, object: nil);
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("makeSpaceForKeyboard:"), name:UIKeyboardWillHideNotification, object: nil);
}

deinit{
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

var keyboardIsVisible = false
override func makeSpaceForKeyboard(notification: NSNotification) {

    let info = notification.userInfo!
    let keyboardHeight:CGFloat = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue().size.height
    let duration:Double = info[UIKeyboardAnimationDurationUserInfoKey] as! Double

    if notification.name == UIKeyboardWillShowNotification && keyboardIsVisible == false{

        keyboardIsVisible = true

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height - keyboardHeight
            self.view.frame = frame
        })

    } else if keyboardIsVisible == true && notification.name == UIKeyboardWillShowNotification{

    }else {
        keyboardIsVisible = false

        UIView.animateWithDuration(duration, animations: { () -> Void in
            var frame = self.view.frame
            frame.size.height = frame.size.height + keyboardHeight
            self.view.frame = frame
        })
    }
}

0

どれもうまくいきませんでした。キーボードが表示されたときに、コンテンツインセットを使用してビューを上に移動しました。

注: UITableViewを使用していた

参照ソリューション@ keyboard-content-offsetは完全に目的Cで記述されており、以下のソリューションはクリーンなSwiftです。

通知オブザーバー@ viewDidLoad()を追加します。

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeShown), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(yourClass.keyboardWillBeHidden), name:UIKeyboardWillHideNotification, object: nil);

キーボードのサイズを取得するには、最初に通知オブジェクトからuserInfoディクショナリを取得します。これには、レシーバーが使用する可能性のある追加のオブジェクトが格納されています。

その辞書から、UIKeyboardFrameBeginUserInfoKeyキーを使用して、キーボードのフレームを記述するCGRectオブジェクトを取得できます。

テーブルビュー@ keyboardWillBeShownメソッドにコンテンツインセットを適用し、

func keyboardWillBeShown(sender: NSNotification)
{        
    // Move the table view

    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
    {
        let contentInsets = UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

        yourTableView.contentInset = contentInsets;

        yourTableView.scrollIndicatorInsets = contentInsets;
    }
}

@ keyboardWillBeHiddenメソッドでビューを復元する

func keyboardWillBeHidden(sender: NSNotification)
{
    // Moving back the table view back to the default position

    yourTableView.contentInset = UIEdgeInsetsZero;

    yourTableView.scrollIndicatorInsets = UIEdgeInsetsZero;
}

デバイスの向きも考慮したい場合は、条件ステートメントを使用して、必要に応じてコードを調整してください。

// Portrait
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.height), 0.0);

// Landscape
UIEdgeInsetsMake(0.0, 0.0, (keyboardSize.width), 0.0);

0
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

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

func keyboardWillShow(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
    }
}

func keyboardWillHide(_ notification:Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
    }
}

ここに画像の説明を入力してください


0

私が使用するSwift 4ソリューションは、キーボードのサイズを採用しています。serverStatusStackView気になるビューに置き換えてください。例self.view::

deinit {
    NotificationCenter.default.removeObserver(self)
}

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

@objc func keyboardWillHide(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        serverStatusStackView.frame.origin.y += keyboardSize.height
    }
}

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

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

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