5
votes

UITableView ajoute la hauteur du clavier au contenu Taille lorsque le clavier apparaît sur iOS11

Je travaille sur un chat qui devrait fonctionner sur iOS 11 et 12. Sur iOS 12, tout fonctionne comme prévu. Sur iOS 11, cependant, j'ai le problème que la taille du contenu de la vue du tableau augmente (pas de cellules) dès que le clavier apparaît. La hauteur supplémentaire correspond à la hauteur du clavier.

Démo

Voici une démo avec iOS 11 à gauche et iOS 12 à droite. Sur iOS 12, tout fonctionne très bien. Faites attention au bas de la vue tableau sur iOS 11 lorsque le clavier est apparu.

 Taille du contenu de la vue tableau iOS 11 Taille du contenu de la vue tableau iOS 12

Afficher / Afficher la configuration de la hiérarchie du contrôleur

- = Afficher le contrôleur
+ = Vue

@objc func handleKeyboardWillShowNotification(_ notification: NSNotification) {
    let frameEnd: CGRect = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue ?? .zero
    let keyboardHeight = frameEnd.height
    let contentHeight = tableView.contentSize.height
    let visibleTableViewHeight = tableView.frame.height - (tableView.contentInset.top + tableView.contentInset.bottom)
    let distanceToScroll = (keyboardHeight - view.safeAreaInsets.bottom)
    var y: CGFloat = 0
    if contentHeight > visibleTableViewHeight {
        y = tableView.contentOffset.y + distanceToScroll
    } else {
        let diff = visibleTableViewHeight - contentHeight
        let positionAtKeyboard = distanceToScroll - tableView.contentInset.top - diff
        y = positionAtKeyboard < tableView.contentInset.top ? -tableView.contentInset.top : positionAtKeyboard
    }
    let contentOffset = CGPoint(x: 0, y: y)
    tableView.contentInset.bottom = keyboardHeight + inputBar.frame.height
    tableView.scrollIndicatorInsets = tableView.contentInset
    tableView.setContentOffset(contentOffset, animated: false)
}

Contraintes de mise en page

Les ancres de la vue tableau sont égales aux ancres de sa supervision. Donc plein écran, ignorant la zone de sécurité. Ainsi, lorsque le clavier apparaît, le cadre ne change pas, mais le contenu du bas est inséré.

Plus de détails

J'ai défini tableView.contentInsetAdjustmentBehavior = .never code >

C'est ainsi que je calcule les inserts et le décalage de la vue du tableau lorsque le clavier apparaît. C'est complexe car il existe plusieurs scénarios où il devrait y avoir un comportement différent. Il existe un calcul complexe similaire lorsque le clavier disparaît et lorsque la hauteur de la saisie de texte change. Je veux toujours faire défiler la vue du tableau vers le haut ou vers le bas en fonction des changements de cadre de vue.

- UINavigationViewController
    - UIViewController // Controlling contentInsets, contentOffset of the tableView
        + UIView
        - UITableViewController
            + UITableView
        - UIViewController // Controlling the text input bar at the bottom
            + ... // Other views
            + UITextView

J'ai également essayé cela sur différentes tailles d'écran et cela ajoute toujours un montant au contentSize qui correspond exactement à la hauteur du clavier.


2 commentaires

Je ne sais pas ce que la version iOS doit faire avec cela, mais comme alternative, vous pouvez utiliser un UITableViewController comme contrôleur principal. Cela a un support intégré pour le clavier évitant le défilement et vous n'avez rien à faire manuellement.


Au lieu d'utiliser l'observateur UIResponder.keyboardDidShowNotification, utilisez UIResponder.keyboardWillChangeFrameNotification pour ios 11 et versions supérieures


3 Réponses :


2
votes

Tout d'abord, vous n'avez pas à faire de calculs inutiles Calculez simplement la hauteur du clavier et déplacez le clavier vers le haut.

Version Swift:

- (void)keyboardWillShow:(NSNotification *)notification
{
    NSDictionary *keyInfo = [notification userInfo];
    CGRect keyboardFrame = [[keyInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardFrame.size.height + 10, 0);

    [UIView animateWithDuration:0.2 animations:^{
        [self.tableView layoutIfNeeded];
        [self.view layoutIfNeeded];
    } completion:nil];
}

- (void) keyboardWillHide:  (NSNotification *) notification
{
    self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
    [UIView animateWithDuration:0.2 animations:^{
        [self.view layoutIfNeeded];
    } completion:nil];
}

Version Objecttive-C:

@objc func keyboardWillShow(notification: NSNotification) {
    if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
        self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height + 10, right: 0)
        UIView.animate(withDuration: 0.25) {
            self.tableView.layoutIfNeeded()
            self.view.layoutIfNeeded()
        }
    }
}

@objc func keyboardWillHide(notification: NSNotification) {

    self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    UIView.animate(withDuration: 0.5) {
        self.tableView.layoutIfNeeded()
        self.view.layoutIfNeeded()
    }
}

Faites-moi savoir si vous rencontrez des difficultés. Cela fonctionne très bien pour moi


0 commentaires

3
votes

Vous pouvez utiliser le code suivant pour masquer et afficher le clavier.

// Afficher le clavier.

@objc func keyboardWillDisappear(_ notification: NSNotification) {
    if self.tableView.contentInset.bottom != 0 {
        self.tableView.contentInset = UIEdgeInsets( top: 0, left: 0, bottom: 0, right: 0 )
        self.tableView.scrollIndicatorInsets = UIEdgeInsets( top: 0, left: 0, bottom: 0, right: 0 )
        UIView.animate(withDuration: 0.1) {
            self.view.layoutIfNeeded()
        }
    }
}

// Cacher le clavier.

@objc func keyboardWillAppear(_ notification: NSNotification) {
    if let newFrame = (notification.userInfo?[ UIResponder.keyboardFrameEndUserInfoKey ] as? NSValue)?.cgRectValue {
        if self.tableView.contentInset.bottom == 0 {
            let insets: UIEdgeInsets = UIEdgeInsets( top: 0, left: 0, bottom: newFrame.height, right: 0 )
            self.tableView.contentInset = insets
            self.tableView.scrollIndicatorInsets = insets
            UIView.animate(withDuration: 0.1) {
                self.view.layoutIfNeeded()
            }
        }
    }
}

C'est du travail pour moi.


3 commentaires

Oui, je place le scrollIndicatorInsets dans la troisième dernière ligne.


@ LukasWürzburger Pouvez-vous vérifier avec ce code ?. Parce que le code ci-dessus fonctionne pour moi. J'ai également eu le même problème.


Avez-vous réellement lu la question? J'ai besoin d'un comportement spécifique dans différentes situations. J'ai vraiment besoin de définir le contentOffset manuellement.



0
votes

Solution de contournement

Cela ne répond pas spécifiquement à la question d'origine, mais pourrait être une solution pour ceux qui ne disposent pas d'un clavier translucide et d'une vue de saisie.

Je pourrais contourner ce problème en modifiant les contraintes et en ne définissant pas les encarts inférieurs. Initialement, la contrainte du bas de la vue de la table était définie en bas de la super vue (bas de l'écran, en gros). Ainsi, lorsque le clavier est apparu, je n'ai pas changé le cadre de la vue du tableau, mais l'encart du bas. Cela n'a apparemment pas fonctionné correctement.

Maintenant, j'ai mis la contrainte du bas de la vue tableau en haut de la vue d'entrée (barre noire) et l'encart du bas à zéro. Étant donné que la vue d'entrée se déplace vers le haut lorsque le clavier apparaît, elle modifie le cadre de la vue de tableau et l'encart inférieur reste à zéro. Je règle toujours le décalage du contenu, car j'ai besoin d'un comportement spécifique dans différentes situations, mais c'est tout.

Cela ne fonctionne que dans ma situation, car je n'ai ni barre de saisie ni clavier translucides et je n'ai pas besoin d'afficher un contenu flou derrière.


0 commentaires