Déplacer une vue vers le haut uniquement lorsque le clavier couvre un champ de saisie

148

J'essaie de créer un écran de saisie pour l'iPhone. L'écran comporte un certain nombre de champs de saisie. La plupart sont en haut de l'écran, mais deux champs sont en bas. Lorsque l'utilisateur essaie de modifier le texte en bas de l'écran, le clavier apparaît et il couvre l'écran. J'ai trouvé une solution simple pour déplacer l'écran vers le haut lorsque cela se produit, mais le résultat est que l'écran se déplace toujours vers le haut et que les champs en haut de l'écran se déplacent hors de portée lorsque l'utilisateur tente de les modifier.

Existe-t-il un moyen de faire bouger l'écran uniquement lorsque les champs du bas sont modifiés?

J'ai utilisé ce code que j'ai trouvé ici :

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
}
John Allijn
la source
peut-être que vous pouvez utiliser func textFieldDidBeginEditing (textField: UITextField!) {} pour détecter quel champ de texte a commencé à être modifié et faire masquer / afficher le clavier
humblePilgrim
J'ai oublié de mentionner que je suis nouveau sur Swift: (Quelle serait la syntaxe correcte pour vérifier cela? (Comment obtenir le nom du champ dans cette fonction?)
John Allijn

Réponses:

211

Votre problème est bien expliqué dans ce document par Apple . Un exemple de code sur cette page (at Listing 4-1) fait exactement ce dont vous avez besoin, il fera défiler votre vue uniquement lorsque l'édition en cours devrait être sous le clavier. Il vous suffit de placer vos contrôles nécessaires dans un scrollViiew. Le seul problème est que c'est Objective-C et je pense que vous en avez besoin dans Swift ... alors ... c'est ici:

Déclarer une variable

var activeField: UITextField?

puis ajoutez ces méthodes

 func registerForKeyboardNotifications()
{
    //Adding notifies on keyboard appearing
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "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)
{
    //Need to calculate keyboard exact size due to Apple suggestions
    self.scrollView.scrollEnabled = true
    var info : NSDictionary = notification.userInfo!
    var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
    var 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 activeFieldPresent = activeField
    {
        if (!CGRectContainsPoint(aRect, activeField!.frame.origin))
        {
            self.scrollView.scrollRectToVisible(activeField!.frame, animated: true)
        }
    }


}


func keyboardWillBeHidden(notification: NSNotification)
{
    //Once keyboard disappears, restore original positions
    var info : NSDictionary = notification.userInfo!
    var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size
    var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.scrollEnabled = false

}

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

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

Assurez-vous de déclarer votre ViewController comme UITextFieldDelegateet de définir les délégués corrects dans vos méthodes d'initialisation: ex:

self.you_text_field.delegate = self

Et n'oubliez pas d'appeler registerForKeyboardNotificationssur viewInit et deregisterFromKeyboardNotificationsà la sortie.

Edition / mise à jour: syntaxe Swift 4.2

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

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

@objc func keyboardWasShown(notification: NSNotification){
    //Need to calculate keyboard exact size due to Apple suggestions
    self.scrollView.isScrollEnabled = true
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 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)
        }
    }
}

@objc func keyboardWillBeHidden(notification: NSNotification){
    //Once keyboard disappears, restore original positions
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.isScrollEnabled = false
}

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

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}
Nerkyator
la source
3
Vous devez appeler registerForKeyboardNotifications à viewDidLoad, vous allez donc ajouter un observateur au centre de notification pour le moment où le clavier apparaît ou disparaît de l'écran. Lorsque ces notifications se déclenchent, les méthodes keyboardWasShown et keyboardWillBeHidden seront appelées, puis scrollview se déplacera en fonction de la taille du clavier. Vous pouvez trouver des informations plus détaillées sur NotificationCenter ici: developer.apple.com/library/mac/documentation/Cocoa/Reference/…
Nerkyator
12
Merci, c'est exactement ce que je recherchais - une solution recommandée par Apple. Cependant, dans mon cas, j'avais déjà une vue de défilement qui s'étendait en dehors de la zone visible. Ce code désactiverait le défilement après le masquage du clavier. J'ai supprimé "self.scrollView.scrollEnabled = false" et il ne défilerait toujours pas. Ce qui a fonctionné pour moi était "self.scrollView.contentInset = UIEdgeInsetsZero;" cette seule ligne dans le clavierWillHide event
F Yaqoob
5
Code parfait. Mais je dois utiliser à la UIKeyboardFrameEndUserInfoKeyplace de UIKeyboardFrameBeginUserInfoKey, car ce dernier retourne la hauteur 0. Et changez le point le plus frappé en bas et non à l'origine. if let activeField = self.activeField { var point = activeField.frame.origin point.y += activeField.frame.size.height if (!aRect.contains(point)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } }
Victor Choy
3
@MaX: Cela devrait fonctionner, mais si vous voulez une solution Swift4, vous pouvez consulter cet exemple iOS du livre de Matt Neuburg que je suggère à tous les développeurs iOS :)
Nerkyator
1
@MaX Je ne suis pas sûr que cela soit exclusivement une 4 chose rapide, mais ce qui semble se produire, c'est que la textField's didBeginEditingméthode est appelée APRÈS que la keyboardWillShowméthode ait été appelée. En conséquence, la activeFieldvariable est toujours nulle, ce qui signifie qu'aucun défilement automatique ne se produit. Ma solution a été de mettre l' activeField = textFieldappel dans la shouldBeginEditingméthode de textField . Cela résout le problème d'ordre des appels.
HirdayGupta
150

Voici mes 2 cents:

Avez-vous essayé: https://github.com/hackiftekhar/IQKeyboardManager

Extrêmement facile à installer Swift ou Objective-C.

Voici comment cela fonctionne:

IQKeyboardManager (Swift): - IQKeyboardManagerSwift est disponible via CocoaPods, pour l'installer, ajoutez simplement la ligne suivante à votre Podfile: (# 236)

pod 'IQKeyboardManagerSwift'

Dans AppDelegate.swift, importez simplement le framework IQKeyboardManagerSwift et activez IQKeyboardManager.

import IQKeyboardManagerSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

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

    IQKeyboardManager.sharedManager().enable = true
    // For Swift 4, use this instead
    // IQKeyboardManager.shared.enable = true


    return true
    }
}

Et c'est tout. Facile!

Monsieur H
la source
17
Parfait. Cela devrait être intégré par défaut. Cela semble ridicule que ce ne soit pas le cas.
NathofGod
1
C'est en fait ridicule, c'est si facile à mettre en œuvre et fonctionne simplement, et vous obtenez un moyen facile de basculer entre plusieurs champs de texte
Khoury
basculer dans plusieurs champs de texte ne fonctionnerait pas? aucune flèche ne s'affiche sur le clavier pour se déplacer entre les champs de texte.
Arsal
1
C'était une solution incroyable, merci! Il m'a fallu un peu de travail pour configurer correctement les CocoaPod, car ils étaient entièrement nouveaux pour moi. Après avoir mis en place cette configuration, il s'agissait littéralement de 2 lignes de code pour l'implémenter et cela a parfaitement fonctionné dès le départ. Merci beaucoup!
IcyBlueRose
5
Cela n'a pas fonctionné pour moi dans Swift 4.1 IQKeyboardManager.sharedManager (). Enable = true A été basculé vers IQKeyboardManager.shared.enable = true
Rmalmoe
20

Celui que j'ai trouvé pour fonctionner parfaitement pour moi était le suivant:

func textFieldDidBeginEditing(textField: UITextField) {
    if textField == email || textField == password {
        animateViewMoving(true, moveValue: 100)
    }
}

func textFieldDidEndEditing(textField: UITextField) {
    if textField == email || textField == password {
        animateViewMoving(false, moveValue: 100)
    }
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
    let movementDuration:NSTimeInterval = 0.3
    let 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()
}

Vous pouvez également modifier les valeurs de hauteur. Supprimez l'instruction "if" si vous souhaitez l'utiliser pour tous les champs de texte.

Vous pouvez même l'utiliser pour tous les contrôles qui nécessitent une entrée utilisateur comme TextView.

Edward
la source
5
Déplacer directement un cadre UIView n'est pas une excellente solution. En outre, cela inclut les valeurs codées en dur qui sont spécifiques à ce cas d'utilisation. J'encourage les gens à ne pas mettre en œuvre une solution comme celle-ci et à faire plutôt quelque chose qui est plus proche des meilleures pratiques comme décrit dans la réponse acceptée.
MobileVet
@MobileVet Compris, mais c'est celui qui fonctionne.
Tarvo Mäesepp
incroyable logique séparée sans changer dans notre code
Dilip Jangid
6

Existe-t-il un moyen d'avoir uniquement l'écran bouger lorsque les champs du bas sont modifiés?

J'ai eu un problème similaire et j'ai trouvé une solution assez simple sans utiliser de scrollView, et à la place en utilisant des instructions if dans les méthodes keyboardWillShow / Hide.

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

C'était une bonne solution pour moi car je n'avais que deux champs de texte.

Décale toute la vue vers le haut: uniquement lorsque certains champs de texte (bottomText) sont modifiés

Décale toute la vue vers le bas: uniquement lorsque la vue n'est pas à l'emplacement d'origine

Villejacob
la source
5

Utilisez simplement cette extension pour déplacer n'importe quel UIView lorsque le clavier est présenté.

extension UIView {
    func bindToKeyboard(){
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillChange(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
    }

    @objc func keyboardWillChange(_ notification: NSNotification){
        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double
        let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt
        let beginningFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
        let endFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue

        let deltaY = endFrame.origin.y - beginningFrame.origin.y

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

Ensuite, dans votre viewdidload liez votre vue au clavier

UiView.bindToKeyboard()
Bilal Mustafa
la source
Cela déplace la vue vers le haut même si ce n'est pas nécessaire et si le champ de texte est en haut de la vue, il montera et ne sera pas visible. Ce n'est pas une bonne solution.
Shivam Pokhriyal
4

Pourquoi ne pas implémenter cela dans un UITableViewController à la place? Le clavier ne masquera aucun champ de texte lorsqu'il est affiché.

RJiryes
la source
c'est en fait le moyen le plus simple et le plus robuste. Et cela fonctionne même avec des contrôles qui utilisent un InputView personnalisé au lieu du clavier par défaut (les notifications UIKeyboard ne fonctionnent pas pour ceux-ci)
Radu Simionescu
1
Il y a le problème que vous devez faire attention, si la vue de table est incorporée (plutôt que d'être "la page entière"). Pour quiconque trébuché par cela, la solution est expliquée dans des articles comme celui-ci et celui-ci . J'espère que cela aidera quelqu'un à faire face au "problème le plus stupide de tout Apple"!
Fattie
3

Swift 4 (** mis à jour ) avec extension **

  1. ajouter les boutons dans un conteneur
  2. connecter la contrainte de fond du conteneur avec IBOutlet containerBtmConstrain
  3. inViewDidLoad

    self.containerDependOnKeyboardBottomConstrain = containerBtmConstrain
    self.watchForKeyboard() 
  4. ajouter l'extension suivante

    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!
            guard let keyboardFrame: CGRect = (info[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
              return
            }
    
            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()
            })
        }
    }
iluvatar_GR
la source
1
Merci mon pote. Tout est question de la bonne clé. J'utilisais UIKeyboardFrameBeginUserInfoKey et maintenant en utilisant UIKeyboardFrameEndUserInfoKey le gère gracieusement.
Felipe
2

J'utilise SwiftLint, qui a eu quelques problèmes avec le formatage de la réponse acceptée. Plus précisément:

pas d'espace avant les deux-points, pas de cast de force, préférez UIEdgeInset (top: etc ... au lieu de UIEdgeInsetMake.

alors voici ces mises à jour pour 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
}
Joe Hoffman
la source
1

Je pense que cet article est faux:

if (!CGRectContainsPoint(aRect, activeField!.frame.origin))

Alors que l'origine de activeField peut bien être au-dessus du clavier, le maxY peut ne pas ...

Je créerais un point «max» pour le activeField et vérifierais si c'est dans le clavier Rect.

zevij
la source
0

Voici ma version après avoir lu la documentation fournie par Apple et les articles précédents. Une chose que j'ai remarquée est que le textView n'était pas géré lorsqu'il était couvert par le clavier. Malheureusement, la documentation d'Apple ne fonctionnera pas car, pour une raison quelconque, le clavier est appelé APRÈS l'appel de textViewDidBeginEditing. J'ai géré cela en appelant une méthode centrale qui vérifie si le clavier est affiché ET si un textView ou textField est en cours d'édition. De cette façon, le processus n'est déclenché que lorsque les DEUX conditions existent.

Un autre point avec textViews est que leur hauteur peut être telle que le clavier coupe le bas du textView et ne s'ajusterait pas si le point Haut-gauche de était en vue. Ainsi, le code que j'ai écrit prend en fait le point en bas à gauche référencé à l'écran de tout textView ou textField et voit s'il se situe dans les coordonnées référencées à l'écran du clavier présenté, ce qui implique que le clavier en couvre une partie.

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

Si vous utilisez un contrôleur de navigation, la sous-classe définit également l'ajustement automatique de la vue de défilement pour les inserts sur false.

self.automaticallyAdjustsScrollViewInsets = false

Il parcourt chaque textView et textField pour définir les délégués à gérer

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

Définissez simplement votre classe de base sur la sous-classe créée ici pour les résultats.

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

}
user2690492
la source
0

Des réponses impressionnantes sont déjà données mais c'est une manière différente de gérer cette situation (en utilisant Swift 3x ):

Tout d'abord, appelez la méthode suivante dans 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)

}

Maintenant, prenez l'une IBOutletdes UIViewprincipales contraintes de votre UIViewcontrollercomme ceci: (voici la sous UIView-vue de UIScrollViewcela signifie que vous devriez avoir un UIScrollViewpour tous vos subViews)

@IBOutlet weak var loginViewTopConstraint: NSLayoutConstraint!

Et une autre variable comme suit et ajoutez un délégué ie UITextFieldDelegate:

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

Après cela, voici la partie magique, collez simplement cet extrait ci-dessous :

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
}

Maintenant, le dernier extrait:

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

N'oubliez pas d'assigner des délégués à tous vos UITextFields inUIStoryboard

Bonne chance!

Anurag Sharma
la source
0

Syntaxe de Swift 3:

func textFieldDidBeginEditing(_ textField: UITextField) {
    // add if for some desired textfields
        animateViewMoving(up: true, moveValue: 100)
}

func textFieldDidEndEditing(_ textField: UITextField) {
    // add if for some desired textfields
        animateViewMoving(up: false, moveValue: 100)
}

func animateViewMoving (up:Bool, moveValue :CGFloat){
     textFieldDidEndEditing(_ textField: UITextField) {

    let movementDuration:TimeInterval = 0.5

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

c'est une bonne méthode pour obtenir ce que vous voulez, vous pouvez ajouter des conditions "si" pour certains champs de texte mais ce type fonctionne pour tous ... J'espère que cela peut être utile pour tout le monde

Atrin Noori
la source
0

Tout d'abord, déclarez une variable pour identifier votre UITextField actif.

Étape 1:-

Comme comme var activeTextField: UITextField?

Étape 2: - Après cela, ajoutez ces deux lignes dans 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)

Étape 3:-

Définissez maintenant ces deux méthodes dans votre classe de contrôleur.

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
}
Hemendra Singh
la source
0

pour swift 4.2.

Cela s'appliquera à n'importe quel formulaire. Pas besoin de scrollview. n'oubliez pas de définir le délégué.

Faire une var de uitextfield

var clickedTextField = UITextField()

Dans votre charge viewdid

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

Connaissez le champ de texte cliqué. vous avez probablement des champs de texte sur tout l'écran.

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

Vérifiez si le clavier couvre le champ de texte ou non.

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

Revenir pour fermer le clavier

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

MISE À JOUR: NSNotification.Name.UIKeyboardWillShow et NSNotification.Name.UIKeyboardWillHide sont renommés respectivement UIResponder.keyboardWillShowNotification et UIResponder.keyboardWillHideNotification.

rupesh45
la source
0

Swift : Vous pouvez le faire en vérifiant quel textField est présenté.

@objc func keyboardWillShow(notification: NSNotification) {
    if self.textField.isFirstResponder == true {
        self.view.frame.origin.y -= 150
     }
}

@objc func keyboardWillHide(notification: NSNotification){
    if self.textField.isFirstResponder == true {
       self.view.frame.origin.y += 150
    }
}
ZAFAR007
la source
-1

Ce code se déplace vers le haut du champ de texte que vous modifiez afin que vous puissiez l'afficher dans Swift 3 pour cette réponse, vous devez également faire de votre vue un UITextFieldDelegate:

var moveValue: CGFloat!
var moved: Bool = false
var activeTextField = UITextField()

func textFieldDidBeginEditing(_ textField: UITextField) {
    self.activeTextField = textField
}
func textFieldDidEndEditing(_ textField: UITextField) {
    if moved == true{
    self.animateViewMoving(up: false, moveValue: moveValue )
        moved = false
    }
}
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()
}

Et puis dans viewDidLoad:

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

Quels appels (hors viewDidLoad):

func keyboardWillShow(notification: Notification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
        let keyboardHeight = keyboardSize.height
        if (view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height < keyboardHeight{
            moveValue = keyboardHeight - ((view.frame.size.height-self.activeTextField.frame.origin.y) - self.activeTextField.frame.size.height)
            self.animateViewMoving(up: true, moveValue: moveValue )
            moved = true
        }
    }
}
JoshLor
la source
-1

Swift 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
}
Alfi
la source
-1

La réponse acceptée est presque parfaite. Mais je dois utiliser UIKeyboardFrameEndUserInfoKeyau lieu de UIKeyboardFrameBeginUserInfoKey,parce que ce dernier retourne la hauteur du keyborad 0. Et change le point le plus frappé vers le bas et non l'origine.

    var aRect : CGRect = self.view.frame
    aRect.size.height -= keyboardSize!.height
    if let activeField = self.activeField {
        var point = activeField.frame.origin
        point.y += activeField.frame.size.height
        if (!aRect.contains(point)){
            self.scrollView.scrollRectToVisible(activeField.frame, animated: true)
        }
    }
Victor Choy
la source
-1

Swift 4 a mis à jour ma solution

avec animation de contrainte sur le clavier afficher / masquer, profitez-en.

import Foundation
import UIKit

class PhoneController: UIViewController, UITextFieldDelegate{

    var phoneLayoutYConstraint: NSLayoutConstraint?

    override func viewDidLoad() {

        super.viewDidLoad()

        view.backgroundColor = .white

        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(handleKeyBoardNotification(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
        phoneField.delegate = self

        view.addSubview(phoneField)

        NSLayoutConstraint.activate([phoneField.heightAnchor.constraint(equalToConstant: 50),
                                     phoneField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
                                     phoneField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
                                     phoneField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)])

        phoneLayoutYConstraint = NSLayoutConstraint(item: phoneField, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
        phoneLayoutYConstraint?.isActive = true

    }

    let phoneField: UITextField = {
        let text = UITextField()
        text.translatesAutoresizingMaskIntoConstraints = false
        text.keyboardType = .numberPad
        text.font = UIFont.systemFont(ofSize: 30)
        text.layer.cornerRadius = 5.0
        text.layer.masksToBounds = true
        text.layer.borderColor = UIColor.darkGray.cgColor
        text.layer.borderWidth = 2.0

        return text
    }()


    override func viewDidDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        NotificationCenter.default.removeObserver(self)
    }

    func textFieldDidBeginEditing(_ textField: UITextField) {

    }


    func textFieldDidEndEditing(_ textField: UITextField) {

    }

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


   @objc func handleKeyBoardNotification(_ notification: NSNotification) {

        if let info = notification.userInfo {

            let keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
            let isKeyBoardShowing = notification.name == NSNotification.Name.UIKeyboardWillShow

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


            phoneLayoutYConstraint?.constant = isKeyBoardShowing ? -keyboardSize!.height : 0

            UIView.animate(withDuration: 0, delay: 0, options: .curveEaseOut, animations: {
                self.view.layoutIfNeeded()
            }, completion: { (boo) in

            })

        }
    }

}
Hattori Hanzō
la source
-1

Swift 4

Vous pouvez facilement monter et descendre UITextFieldavec le clavier avec animation

entrez la description de l'image ici

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)
    }
ZAFAR007
la source
Encore une fois, une solution qui poussera la vue vers le haut inutilement, même lorsqu'elle n'est pas nécessaire. S'il vous plaît améliorer votre réponse, il est trompeur
Shivam Pokhriyal
-1

Swift 4.2

Ma solution centrera (verticalement) la vue sur a UITextFieldsi sa position est sous le clavier.

Étape 1: Créez un nouveau fichier Swift et une UIViewWithKeyboardclasse copier-coller .
Étape 2: Dans Interface Builder, définissez-le comme une classe personnalisée pour vos meilleurs UIView.

import UIKit

class UIViewWithKeyboard: UIView {
    @IBInspectable var offsetMultiplier: CGFloat = 0.75
    private var keyboardHeight = 0 as CGFloat
    private weak var activeTextField: UITextField?
    override func awakeFromNib() {
        super.awakeFromNib()
        NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.textDidBeginEditing),
                                               name: UITextField.textDidBeginEditingNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillShow),
                                               name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(UIViewWithKeyboard.keyboardWillHide),
                                               name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    @objc func textDidBeginEditing(_ notification: NSNotification) {
        self.activeTextField = notification.object as? UITextField
    }

    @objc func keyboardWillShow(_ notification: Notification) {
        if let frameValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            keyboardHeight = frameValue.cgRectValue.size.height
            if let textField = self.activeTextField {
                let offset = textField.frame.maxY < frame.maxY - keyboardHeight ? 0
                           : textField.frame.maxY - (frame.maxY - keyboardHeight) * offsetMultiplier
                self.setView(offset: offset)
            }
        }
    }

    @objc func keyboardWillHide(_ notification: NSNotification) {
        self.setView(offset: 0)
    }

    func setView(offset: CGFloat) {
        UIView.animate(withDuration: 0.25) {
            self.bounds.origin.y = offset
        }
    }
}
portée
la source
-1

Réécrit pour swift 4.2

Dans ViewDidLoad ..

 NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWasShown), name: UIResponder.keyboardWillShowNotification, object: nil)
 NotificationCenter.default.addObserver(self, selector: #selector(trailViewController.keyboardWillBeHidden), name: UIResponder.keyboardWillHideNotification, object: nil)

Fonctions restantes

func registerForKeyboardNotifications(){
    //Adding notifies on keyboard appearing
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

func deregisterFromKeyboardNotifications(){
    //Removing notifies on keyboard appearing
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}

@objc func keyboardWasShown(notification: NSNotification){
    //Need to calculate keyboard exact size due to Apple suggestions
    self.scrollView.isScrollEnabled = true
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 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)
        }
    }
}

@objc func keyboardWillBeHidden(notification: NSNotification){
    //Once keyboard disappears, restore original positions
    var info = notification.userInfo!
    let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0)
    self.scrollView.contentInset = contentInsets
    self.scrollView.scrollIndicatorInsets = contentInsets
    self.view.endEditing(true)
    self.scrollView.isScrollEnabled = false
}

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

func textFieldDidEndEditing(_ textField: UITextField){
    activeField = nil
}
VarunRaj
la source
-2

"J'ai oublié de mentionner que je suis nouveau sur Swift :( Quelle serait la syntaxe correcte pour vérifier cela? (Comment obtenir le nom de champ dans cette fonction?)"

D'accord . Confirmez d'abord au protocole UITextFieldDelegate

class YourClass:UITextFieldDelegate

Puis implémentez la fonction

func textFieldDidBeginEditing(textField: UITextField!) {

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

Vous devez noter que la bonne approche consiste à utiliser une vue de défilement et à placer la vue qui doit être déplacée vers le haut / bas dans la vue de défilement et à gérer les événements de clavier en conséquence

humblePilgrim
la source
-3

Pour Swift 4.2

Ce code vous permettra de contrôler le moment de l'axe Y du cadre pour une taille d'écran de périphérique spécifique.

PS: Ce code ne déplacera pas intelligemment le cadre en fonction de l'emplacement de TextField.

Créer une extension pour UIDevice

extension UIDevice {
    enum ScreenType: String {
        case iPhone4_4S = "iPhone 4 or iPhone 4s"
        case iPhones_5_5s_5c_SE = "iPhone 5, iPhone 5s, iPhone 5c or iPhone SE"
        case iPhones_6_6s_7_8 = "iPhone 6, iPhone 6s, iPhone 7 or iPhone 8"
        case iPhones_6Plus_6sPlus_7Plus_8Plus = "iPhone 6 Plus, iPhone 6s Plus, iPhone 7 Plus or iPhone 8 Plus"
        case iPhoneX_Xs = "iPhone X, iPhone Xs"
        case iPhoneXR = "iPhone XR"
        case iPhoneXSMax = "iPhone Xs Max"
        case unknown
    }
    var screenType: ScreenType {
        switch UIScreen.main.nativeBounds.height {
        case 960:
            return .iPhone4_4S
        case 1136:
            return .iPhones_5_5s_5c_SE
        case 1334:
            return .iPhones_6_6s_7_8
        case 1920, 2208:
            return .iPhones_6Plus_6sPlus_7Plus_8Plus
        case 1792:
            return .iPhoneXR
        case 2436:
            return .iPhoneX_Xs
        case 2688:
            return .iPhoneXSMax
        default:
            return .unknown
        }
    }
}

Ajouter NotificationObserver sur 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)

Sélecteur

@objc func keyboardWillShow(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        if self.view.frame.origin.y == 0 {
            switch (UIDevice.current.screenType.rawValue) {
            case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
                self.view.frame.origin.y -= 210
            case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
                self.view.frame.origin.y -= 110
            case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
                self.view.frame.origin.y -= 80
            case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
                self.view.frame.origin.y -= 70
            case (UIDevice.ScreenType.iPhoneXR.rawValue):
                self.view.frame.origin.y -= 70
            case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
                self.view.frame.origin.y -= 70
            default:
                self.view.frame.origin.y -= 150
            }
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {
    if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
        if self.view.frame.origin.y != 0 {
            switch (UIDevice.current.screenType.rawValue) {
            case (UIDevice.ScreenType.iPhones_5_5s_5c_SE.rawValue):
                self.view.frame.origin.y += 210
            case (UIDevice.ScreenType.iPhones_6_6s_7_8.rawValue):
                self.view.frame.origin.y += 110
            case (UIDevice.ScreenType.iPhones_6Plus_6sPlus_7Plus_8Plus.rawValue):
                self.view.frame.origin.y += 80
            case (UIDevice.ScreenType.iPhoneX_Xs.rawValue):
                self.view.frame.origin.y += 70
            case (UIDevice.ScreenType.iPhoneXR.rawValue):
                self.view.frame.origin.y += 70
            case (UIDevice.ScreenType.iPhoneXSMax.rawValue):
                self.view.frame.origin.y += 70
            default:
                self.view.frame.origin.y += 150
            }
        }
    }
}
Kavin Varnan
la source
1
En général, je dirais que c'est une approche mauvaise et plutôt coûteuse d'utiliser des types spécifiques de périphérique et des dimensions liées à la disposition du code en dur à mesure qu'elles changent.
Johan le