ios ipad pro - キーボードが入力フィールドをカバーしている場合にのみビューを上に移動する





11 Answers

ここに私の2セントです:

試してみましたか: https://github.com/hackiftekhar/IQKeyboardManager : https://github.com/hackiftekhar/IQKeyboardManager

SwiftまたはObjective-Cのインストールが非常に簡単です。

ここでどのように動作する:

IQKeyboardManager(Swift): - IQKeyboardManagerSwiftは、Podfileに次の行を追加するだけで、CocoaPodsからインストールできます。(#236)

pod 'IQKeyboardManagerSwift'

AppDelegate.swiftでは、IQKeyboardManagerSwiftフレームワークをインポートし、IQKeyboardManagerを有効にするだけです。

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

    IQKeyboardManager.sharedManager().enable = true

    return true
    }
}

それがすべてです。 簡単!

設定 分割 位置

私はiPhone用の入力画面を構築しようとしています。 画面にはいくつかの入力フィールドがあります。 それらのほとんどは画面の上部にありますが、2つのフィールドは下部にあります。 ユーザーが画面の下のテキストを編集しようとすると、キーボードがポップアップして画面をカバーします。 このようなときに画面を移動する簡単な解決策が見つかりましたが、その結果、ユーザーが画面を編集しようとすると画面が常に上に移動し、画面上部のフィールドが外に移動します。

下のフィールドが編集されたときにのみ画面を移動させる方法はありますか?

私はhere見つけhereこのコードを使用しましhere

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(sender: NSNotification) {
self.view.frame.origin.y -= 150
}

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



下のフィールドが編集されたときにのみ画面を移動させる方法はありますか?

同様の問題があり、scrollView 使用せずに、代わりにkeyboardWillShow / Hideメソッド内のifステートメント使用することで 、かなり簡単な解決策が見つかりました。

func keyboardWillShow(notification: NSNotification) {
    if bottomText.editing{
        self.view.window?.frame.origin.y = -1 * getKeyboardHeight(notification)
    }
}

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

私は2つのテキストフィールドしか持たなかったので、これは私にとっては良い解決策でした。

ビュー全体を上にシフト:特定のテキストフィールド(bottomText)が編集されたときのみ

ビュー全体を下にシフト:ビューが元の位置にない場合のみ




スウィフト4(**更新 )と拡張機能**

  1. 1つのコンテナにボタンを追加する
  2. コンテナの下限制約をIBOutletコンテナに接続します.BtmConstrain
  3. inViewDidLoad

    self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
    self.watchForKeyboard() 
    
  4. 次の拡張子を追加してください

    import UIKit
    
    private var xoAssociationKeyForBottomConstrainInVC: UInt8 = 0
    
    extension UIViewController {
    
     var containerDependOnKeyboardBottomConstrain :NSLayoutConstraint! {
      get {
        return objc_getAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC) as? NSLayoutConstraint
      }
      set(newValue) {
        objc_setAssociatedObject(self, &xoAssociationKeyForBottomConstrainInVC, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
      }
     }
    
     func watchForKeyboard () {
       NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown(notification:)), name:UIResponder.keyboardWillShowNotification, object: nil);
       NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(notification:)), name:UIResponder.keyboardWillHideNotification, object: nil);
     }
    
     @objc func keyboardWasShown(notification: NSNotification) {
      let info = notification.userInfo!
      let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
    
      UIView.animate(withDuration: 0.3, animations: { () -> Void in
        self.containerDependOnKeyboardBottomConstrain.constant = -keyboardFrame.height
        self.view.layoutIfNeeded()
      })
     }
    
     @objc func keyboardWillHide(notification: NSNotification) {
        UIView.animate(withDuration: 0.3, animations: { () -> Void in
        self.containerDependOnKeyboardBottomConstrain.constant = 0
        self.view.layoutIfNeeded()
      })
     }
    }
    



SwiftLintを使用しましたが、これには受け入れられた回答のフォーマットに関するいくつかの問題がありました。 具体的には:

コロンの前に空白を入れないでください。強制的にキャストしないでください。UIEdgeInsetMakeの代わりにUIEdgeInset(top:etc ...)を使用してください。

ここにSwift 3のアップデートがあります

func registerForKeyboardNotifications() {
    //Adding notifies on keyboard appearing
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func deregisterFromKeyboardNotifications() {
    //Removing notifies on keyboard appearing
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

func keyboardWasShown(notification: NSNotification) {
    //Need to calculate keyboard exact size due to Apple suggestions
    scrollView?.isScrollEnabled = true
    var info = notification.userInfo!
    if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
        let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize.height, right: 0.0)

        scrollView?.contentInset = contentInsets
        scrollView?.scrollIndicatorInsets = contentInsets

        var aRect: CGRect = self.view.frame
        aRect.size.height -= keyboardSize.height
        if let activeField = self.activeField {
            if !aRect.contains(activeField.frame.origin) {
                self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
            }
        }
    }
}

func keyboardWillBeHidden(notification: NSNotification) {
    //Once keyboard disappears, restore original positions
    var info = notification.userInfo!
    if let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size {
        let contentInsets: UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize.height, right: 0.0)
        scrollView?.contentInset = contentInsets
        scrollView?.scrollIndicatorInsets = contentInsets
    }

    view.endEditing(true)
    scrollView?.isScrollEnabled = false
}

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

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



ここで私のバージョンはAppleと以前の投稿によって提供されたドキュメントを読んだ後です。 私が気づいたことの1つは、textViewがキーボードで覆われていると処理されなかったことです。 残念ながら、何らかの理由で、textViewDidBeginEditingが呼び出された後にキーボードが呼び出されるため、Appleのドキュメントは機能しません。 私は、キーボードが表示されているかどうか、textViewまたはtextFieldが編集中であるかどうかをチェックする中心的なメソッドを呼び出すことでこれを処理しました。 この方法では、プロセスは両方の条件が存在する場合にのみ起動されます。

textViewsの別のポイントは、キーボードの高さがtextViewの下端をクリップし、その上端の点が表示されている場合に調整しないことです。 だから、私が書いたコードは実際には、text-viewまたはtextFieldのスクリーン参照されたBottom-Leftポイントをとり、それがキーボードのある部分を覆っていることを意味する提示されたキーボードのスクリーン参照座標に含まれるかどうかを調べます。

let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
    if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY))) {
        // scroll textView/textField into view
    }

ナビゲーションコントローラを使用している場合、サブクラスは、インセットのスクロールビュー自動調整をfalseに設定します。

self.automaticallyAdjustsScrollViewInsets = false

これは、各textViewとtextFieldを処理して、デリゲートを処理するように設定します

    for view in self.view.subviews {
        if view is UITextView {
            let tv = view as! UITextView
            tv.delegate = self
        } else if view is UITextField {
            let tf = view as! UITextField
            tf.delegate = self
        }
    }

基本クラスを結果用にここで作成したサブクラスに設定するだけです。

import UIKit

class ScrollingFormViewController: UIViewController, UITextViewDelegate, UITextFieldDelegate {

var activeFieldRect: CGRect?
var keyboardRect: CGRect?
var scrollView: UIScrollView!

override func viewDidLoad() {

    self.automaticallyAdjustsScrollViewInsets = false

    super.viewDidLoad()

    // Do any additional setup after loading the view.
    self.registerForKeyboardNotifications()
    for view in self.view.subviews {
        if view is UITextView {
            let tv = view as! UITextView
            tv.delegate = self
        } else if view is UITextField {
            let tf = view as! UITextField
            tf.delegate = self
        }
    }
    scrollView = UIScrollView(frame: self.view.frame)
    scrollView.scrollEnabled = false
    scrollView.showsVerticalScrollIndicator = false
    scrollView.showsHorizontalScrollIndicator = false
    scrollView.addSubview(self.view)
    self.view = scrollView
}

override func viewDidLayoutSubviews() {
    scrollView.sizeToFit()
    scrollView.contentSize = scrollView.frame.size
    super.viewDidLayoutSubviews()
}

deinit {
    self.deregisterFromKeyboardNotifications()
}

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


func registerForKeyboardNotifications()
{
    //Adding notifies on keyboard appearing
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWasShown), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ScrollingFormViewController.keyboardWillBeHidden), name: UIKeyboardWillHideNotification, object: nil)
}


func deregisterFromKeyboardNotifications()
{
    //Removing notifies on keyboard appearing
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}

func keyboardWasShown(notification: NSNotification)
{
    let info : NSDictionary = notification.userInfo!
    keyboardRect = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue()
    adjustForKeyboard()
}


func keyboardWillBeHidden(notification: NSNotification)
{
    keyboardRect = nil
    adjustForKeyboard()
}

func adjustForKeyboard() {
    if keyboardRect != nil && activeFieldRect != nil {
        let aRect : CGRect = scrollView.convertRect(activeFieldRect!, toView: nil)
        if (CGRectContainsPoint(keyboardRect!, CGPointMake(aRect.origin.x, aRect.maxY)))
        {
            scrollView.scrollEnabled = true
            let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardRect!.size.height, 0.0)
            scrollView.contentInset = contentInsets
            scrollView.scrollIndicatorInsets = contentInsets
            scrollView.scrollRectToVisible(activeFieldRect!, animated: true)
        }
    } else {
        let contentInsets : UIEdgeInsets = UIEdgeInsetsZero
        scrollView.contentInset = contentInsets
        scrollView.scrollIndicatorInsets = contentInsets
        scrollView.scrollEnabled = false
    }
}

func textViewDidBeginEditing(textView: UITextView) {
    activeFieldRect = textView.frame
    adjustForKeyboard()
}

func textViewDidEndEditing(textView: UITextView) {
    activeFieldRect = nil
    adjustForKeyboard()
}

func textFieldDidBeginEditing(textField: UITextField)
{
    activeFieldRect = textField.frame
    adjustForKeyboard()
}

func textFieldDidEndEditing(textField: UITextField)
{
    activeFieldRect = nil
    adjustForKeyboard()
}

}



恐ろしい答えがすでに与えられていますが、これは( Swift 3xを使用して)この状況に対処する別の方法です。

まず、 viewWillAppear()で次のメソッドを呼び出します。

func registerForKeyboardNotifications() {

NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWasShown), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillBeHidden), name: NSNotification.Name.UIKeyboardWillHide, object: nil)

}

ここであなたのIBOutletUIViewのトップIBOutletの1つのIBOutletUIViewcontrollerようにします(ここでUIViewはすべてのサブビューに対してUIScrollViewを持つべきであることを意味するUIScrollViewのサブビューです)

@IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!

次のような別の変数を使用して、代理人、つまりUITextFieldDelegateを追加しUITextFieldDelegate

var activeTextField = UITextField() //This is to keep the reference of UITextField currently active

その後、ここに魔法の部分がスニペットの下に貼り付けられます:

func keyboardWasShown(_ notification: Notification) {

let keyboardInfo  = notification.userInfo as NSDictionary?

//print(keyboardInfo!)

let keyboardFrameEnd: NSValue? = (keyboardInfo?.value(forKey: UIKeyboardFrameEndUserInfoKey) as? NSValue)

let keyboardFrameEndRect: CGRect? = keyboardFrameEnd?.cgRectValue


if activeTextField.frame.origin.y + activeTextField.frame.size.height + 10 > (keyboardFrameEndRect?.origin.y)! {

    UIView.animate(withDuration: 0.3, delay: 0, options: .transitionFlipFromTop, animations: {() -> Void in

        //code with animation

        //Print some stuff to know what is actually happening
        //print(self.activeTextField.frame.origin.y)
        //print(self.activeTextField.frame.size.height)
        //print(self.activeTextField.frame.size.height)

        self.loginViewTopConstraint.constant = -(self.activeTextField.frame.origin.y + self.activeTextField.frame.size.height - (keyboardFrameEndRect?.origin.y)!) - 30.0

        self.view.layoutIfNeeded()

    }, completion: {(_ finished: Bool) -> Void in
        //code for completion

    })
}
}

func keyboardWillBeHidden(_ notification: Notification) {

UIView.animate(withDuration: 0.3, animations: {() -> Void in

    self.loginViewTopConstraint.constant = self.view.frame.origin.y
    self.view.layoutIfNeeded()

})
}

//MARK: textfield delegates
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    activeTextField = textField
    return true
}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {

           switch textField {
    case YOUR_TEXTFIELD_ONE:
        YOUR_TEXTFIELD_TWO.becomeFirstResponder()
        break
    case YOUR_TEXTFIELD_TWO:
        YOUR_TEXTFIELD_THREE.becomeFirstResponder()
        break
    default:
        textField.resignFirstResponder()
        break
    }
    return true
}

今最後のスニペット:

//Remove Keyboard Observers
override func viewWillDisappear(_ animated: Bool) {

NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)

NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}

UIStoryboard内のすべてのUITextFieldに代理人を割り当てることを忘れないでください

がんばろう!




「私はSwiftの新機能について言及していませんでした。(これをチェックする正しい構文は何でしょうか?(この関数でフィールド名を取得する方法は?)

OK 。 最初にUITextFieldDelegateプロトコルを確認する

class YourClass:UITextFieldDelegate

次に、関数を実装します。

func textFieldDidBeginEditing(textField: UITextField!) {

    if textField == txtOne
    {
        println("TextOne")
    }
    if textField == txtTwo
    {
        println("TextTwo")
    }
}

適切な方法は、スクロールビューを使用し、スクロールビュー内で上下に移動する必要があるビューを配置し、それに応じてキーボードイベントを処理することです




スウィフト3

@IBOutlet var scrollView: UIScrollView!
@IBOutlet var edtEmail: UITextField!
@IBOutlet var bottomTextfieldConstrain: NSLayoutConstraint! // <- this guy is the constrain that connect the bottom of textField to lower object or bottom of page!

 @IBAction func edtEmailEditingDidBegin(_ sender: Any) { 
        self.bottomTextfieldConstrain.constant = 200
        let point = CGPoint(x: 0, y: 200)
        scrollView.contentOffset = point
    }

@IBAction func edtEmailEditingDidEnd(_ sender: Any) { 
    self.bottomTextfieldConstrain.constant = 50
}



まず、アクティブなUITextFieldを識別するための変数を宣言します。

ステップ1:-

var activeTextField: UITextField

ステップ2:この後、これらの2行をviewDidLoadに追加します。

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)

ステップ3: -

これらの2つのメソッドをコントローラクラスに定義します。

func keyboardWillShow(_ notification: NSNotification) {

    self.scrollView.isScrollEnabled = true
    var info = notification.userInfo!
    let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0)

    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets

    var aRect : CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height
    if let activeField = self.activeField {
        if (!aRect.contains(activeField.frame.origin)){
            self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
        }
    }
}


func keyboardWillHide(_ notification: NSNotification) {

    let contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, 0.0, 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.isScrollEnabled = true
}


func textFieldDidBeginEditing(_ textField: UITextField){

    activeField = textField
}

func textFieldDidEndEditing(_ textField: UITextField){

    activeField = nil
}



スウィフト4

UITextFieldアニメーションでキーボードを使って簡単に上下に移動できます

import UIKit

class ViewController: UIViewController {

    @IBOutlet var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        textField.resignFirstResponder()
    }

    @objc func keyboardWillChange(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
        let deltaY = targetFrame.origin.y - curFrame.origin.y

        UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: {
            self.textField.frame.origin.y+=deltaY

        },completion: nil)
    }



速攻4のために。

これはどのフォームにも当てはまります。スクロールビューの必要はありません。

// uitextfieldのvarを作る

var clickedTextField = UITextField()

//あなたのviewdidのload

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

//クリックされたテキストフィールドを知る。おそらくあなたは画面全体にテキストフィールドを持っています。

 func textFieldDidBeginEditing(_ textField: UITextField) {


            clickedTextField = textField


}

//キーボードがテキストフィールドをカバーしているかどうかを確認します。

 @objc func keyboardWillShow(sender: NSNotification,_ textField : UITextField) {
    if let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {

        if clickedTextField.frame.origin.y > keyboardSize.origin.y {
            self.view.frame.origin.y = keyboardSize.origin.y - clickedTextField.center.y - 20
        }
    }


}

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

//キーボードを閉じて戻る

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



Related