web-dev-qa-db-fra.com

Scrollview et clavier Swift

Je suis nouveau ici et je commence par Swift pour iOS.

J'ai commencé à créer une application simple qui effectue certaines opérations. Mais je rencontre des problèmes lorsque le clavier apparaît, masquant l'un de mes champs de texte. Je pense que c'est un problème commun et j'ai fait quelques recherches mais je n'ai rien trouvé qui résout mon problème. Et je veux utiliser un défilement plutôt que d’animer le champ textField pour le rendre visible.

Merci !!!!! (Désolé pour les fautes d'anglais)

36
GalinhaVoadora

Dans ViewDidLoad, enregistrez les notifications:

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

Ajoutez ci-dessous les méthodes de l'observateur qui effectuent le défilement automatique lorsque le clavier apparaît.

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

func keyboardWillShow(notification:NSNotification){

    var userInfo = notification.userInfo!
    var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue()
    keyboardFrame = self.view.convertRect(keyboardFrame, fromView: nil)

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

func keyboardWillHide(notification:NSNotification){

    let contentInset:UIEdgeInsets = UIEdgeInsetsZero
    scrollView.contentInset = contentInset
}

EDIT: Ce message a été mis à jour pour refléter les meilleures pratiques de Swift 2.2 pour les sélecteurs Objective C.

101
Sudheer Palchuri

La meilleure réponse pour Swift 3:

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)

Et alors: 

func keyboardWillShow(notification:NSNotification){
    //give room at the bottom of the scroll view, so it doesn't cover up anything the user needs to tap
    var userInfo = notification.userInfo!
    var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    keyboardFrame = self.view.convert(keyboardFrame, from: nil)

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

func keyboardWillHide(notification:NSNotification){
    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    theScrollView.contentInset = contentInset
}
61
Daniel Jones

Voici une solution complète dans Swift 4, utilisant un code de garde et un code concis. Plus le code correct dans keyboardWillHide pour réinitialiser uniquement la bottom à 0.

@IBOutlet weak var scrollView: UIScrollView!

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

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

private func registerNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}

private func unregisterNotifications() {
    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 keyboardFrame = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
    scrollView.contentInset.bottom = view.convert(keyboardFrame.cgRectValue, from: nil).size.height
}

@objc func keyboardWillHide(notification: NSNotification){
    scrollView.contentInset.bottom = 0
}
10
Harris

pour Swift 4.0

Dans ViewDidLoad

// setup keyboard event
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name:UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name:UIResponder.keyboardWillHideNotification, object: nil)

Ajoutez ci-dessous les méthodes de l'observateur qui effectuent le défilement automatique lorsque le clavier apparaît.

@objc func keyboardWillShow(notification:NSNotification){
    var userInfo = notification.userInfo!
    var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue
    keyboardFrame = self.view.convert(keyboardFrame, from: nil)

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

@objc func keyboardWillHide(notification:NSNotification){

    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    ui_scrollView.contentInset = contentInset
}
9

contentInset ne fonctionne pas pour moi, car je souhaite que la vue de défilement se déplace au-dessus du clavier. Donc j'utilise contentOffset:

func keyboardWillShow(notification:NSNotification) {
    guard let keyboardFrameValue = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue else {
        return
    }
    let keyboardFrame = view.convert(keyboardFrameValue.cgRectValue, from: nil)
    scrollView.contentOffset = CGPoint(x:0, y:keyboardFrame.size.height)
}

func keyboardWillHide(notification:NSNotification) {
    scrollView.contentOffset = .zero
}
6
nikans

En lisant les liens que vous m'avez envoyés, j'ai trouvé un moyen de le faire fonctionner, merci !:

func textFieldDidBeginEditing(textField: UITextField) {            
    if (textField == //your_field) {
        scrollView.setContentOffset(CGPointMake(0, field_extra.center.y-280), animated: true)
        callAnimation()
        viewDidLayoutSubviews()
    }
}

func textFieldDidEndEditing(textField: UITextField) {    
    if (textField == //your_field){
        scrollView .setContentOffset(CGPointMake(0, 0), animated: true)
        viewDidLayoutSubviews()
    }
}
4
GalinhaVoadora

D'après la réponse de Sudheer Palchuri, converti en Swift 4.

Dans ViewDidLoad, enregistrez les notifications: 

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)

Et alors:

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

@objc func keyboardWillShow(notification:NSNotification){

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

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

@objc func keyboardWillHide(notification:NSNotification){

    let contentInset:UIEdgeInsets = UIEdgeInsets.zero
    self.scrollView.contentInset = contentInset
}
3
Ivan Carosati

Vous pouvez animer votre défilement pour qu’il se centre sur votre UITextField sur l’apparence du clavier (c’est-à-dire que votre champ de texte devienne le premier répondant) via un décalage de défilement. Voici quelques bonnes ressources pour vous aider à démarrer (il y en a beaucoup sur ce site): 

Comment déplacer par programme un UIScrollView pour qu'il se concentre sur un contrôle situé au-dessus du clavier?

Comment faire défiler automatiquement UIScrollView lorsqu'un UITextField devient le premier répondant

En outre, si vous utilisez simplement un UITableView avec votre contenu dans des cellules, lorsque le champ de texte devient le premier répondeur, UITableViewController défilera automatiquement vers la cellule de champ de texte pour vous (bien que je ne sois pas sûr que ce soit ce que vous souhaitiez faire).

2
Glynbeard

Une réponse pour Swift 3, basée sur celle proposée par Daniel Jones, mais plus sûre (grâce au gardien), plus concise et avec des encarts d'indicateur de défilement cohérents:

@objc private func keyboardWillBeShown(notification: NSNotification) {
    guard let keyboardFrameValue = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue else { return }
    let keyboardFrame = view.convert(keyboardFrameValue.cgRectValue, from: nil)
    scrollView.contentInset.bottom = keyboardFrame.size.height
    scrollView.scrollIndicatorInsets = scrollView.contentInset
}

@objc private func keyboardWillBeHidden() {
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = scrollView.contentInset
}
1
Johan Drevet

Si vous recherchez du code Objective-C pour cette solution:

- (void)keyboardWasShown:(NSNotification *)notification {
        NSDictionary* info = [notification userInfo];
        CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
        UIEdgeInsets contentInsets = baseScrollView.contentInset;
        contentInsets.bottom = kbSize.height;
        baseScrollView.contentInset = contentInsets;
    }

    - (void)keyboardWillBeHidden:(NSNotification *)notification {
        UIEdgeInsets contentInsets = UIEdgeInsetsZero;
        baseScrollView.contentInset = contentInsets;
        [baseScrollView endEditing:YES];
    }
0
Mubeen Qazi

Dans Swift4, ajoutez simplement l'extension suivante.

extension UIViewController {

   func setupViewResizerOnKeyboardShown() {
        NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillShowForResizing),
                                           name: 
        Notification.Name.UIKeyboardWillShow,
                                           object: nil)
        NotificationCenter.default.addObserver(self,
                                           selector: #selector(self.keyboardWillHideForResizing),
                                           name: Notification.Name.UIKeyboardWillHide,
                                           object: nil)
        }

   @objc func keyboardWillShowForResizing(notification: Notification) {
        if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue,
        let window = self.view.window?.frame {
        // We're not just minusing the kb height from the view height because
        // the view could already have been resized for the keyboard before
        self.view.frame = CGRect(x: self.view.frame.Origin.x,
                                 y: self.view.frame.Origin.y,
                                 width: self.view.frame.width,
                                 height: window.Origin.y + window.height - keyboardSize.height)
      } else {
        debugPrint("We're showing the keyboard and either the keyboard size or window is nil: panic widely.")
      }
  }

   @objc func keyboardWillHideForResizing(notification: Notification) {
     if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        let viewHeight = self.view.frame.height
        self.view.frame = CGRect(x: self.view.frame.Origin.x,
                                 y: self.view.frame.Origin.y,
                                 width: self.view.frame.width,
                                 height: viewHeight + keyboardSize.height)
    } else {
        debugPrint("We're about to hide the keyboard and the keyboard size is nil. Now is the rapture.")
    }
   }
 }
0
Sam
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
Zany