Comportement uitableview bizarre dans iOS11. Les cellules défilent vers le haut avec l'animation de poussée de navigation

J'ai récemment migré du code vers le nouveau SDK iOS 11 beta 5.

J'ai maintenant un comportement très déroutant de UITableView. Le tableview lui-même n'est pas si chic. J'ai des cellules personnalisées mais dans la plupart des cas, c'est juste pour leur taille.

Lorsque je pousse mon contrôleur de vue avec tableview, je reçois une animation supplémentaire où les cellules "défilent" (ou peut - être que tout le cadre tableview est changé) et vers le bas le long de l'animation de navigation push/pop. Veuillez voir gif:

ondulés tableview

Je crée manuellement tableview dans la méthode loadView et configure les contraintes de mise en page automatique pour être égales à leading, trailing, top, bottom of tableview's superview. Le superview est la vue racine du contrôleur de vue.

Le code poussant du contrôleur de vue est très standard: self.navigationController?.pushViewController(notifVC, animated: true)

Le même code fournit un comportement normal sur iOS 10.

Pourriez-vous m'indiquer ce qui ne va pas?

EDIT: j'ai fait un tableview très simple contrôleur et je peux reproduire le même comportement là. Code:

class VerySimpleTableViewController : UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }


    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 4
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)

        cell.textLabel?.text = String(indexPath.row)
        cell.accessoryType = .disclosureIndicator

        return cell
    }


    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)

        let vc = VerySimpleTableViewController.init(style: .grouped)

        self.navigationController?.pushViewController(vc, animated: true)
    }
}

EDIT 2: j'ai pu réduire le problème à ma personnalisation de UINavigationBar. J'ai une personnalisation comme ceci:

rootNavController.navigationBar.setBackgroundImage(createFilledImage(withColor: .white, size: 1), for: .default)

createFilledImage crée une image carrée avec une taille et une couleur Données.

Si je commente cette ligne, je retrouve un comportement normal.

J'apprécierais toute réflexion à ce sujet.

105
demandé sur iur 2017-08-08 19:44:45

10 réponses

Cela est dû à UIScrollView's (UITableView est une sous-classe de UIScrollview) nouveau contentInsetAdjustmentBehavior la propriété, qui est fixé à .automatic par défaut.

Vous pouvez remplacer ce comportement avec l'extrait suivant dans viewDidLoad de tous les contrôleurs affectés:

    tableView.contentInsetAdjustmentBehavior = .never

Https://developer.apple.com/documentation/uikit/uiscrollview/2902261-contentinsetadjustmentbehavior

134
répondu Maggy Hillen 2017-10-30 14:52:02

En plus de la réponse de maggy

OBJECTIF-C

if (@available(iOS 11.0, *)) {
    scrollViewForView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}

Ce problème a été causé par un bug dans iOS 11 où le safeAreaInsets de la vue du contrôleur de vue a été mal définie pendant la navigation transition, qui devrait être fixé dans iOS 11.2. Réglage de la contentInsetAdjustmentBehavior à .never n'est pas une bonne solution parce qu'il aura probablement d'autres effets secondaires indésirables. Si vous ne utilisez une solution de contournement, vous devez vous assurer de le supprimer pour les versions iOS > = 11.2

-Il s'agit de l'un des plus grands logiciels D'Apple.]}

20
répondu Lal Krishna 2018-03-25 07:26:37

Vous pouvez modifier ce comportement à la fois tout au long de l'application en utilisant NSProxy dans par exemple didFinishLaunchingWithOptions:

if (@available(iOS 11.0, *)) {
      [UIScrollView appearance].contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} 
6
répondu BigDanceMouse 2017-10-09 16:17:06

Cela ressemble plus à un bug qu'à un comportement prévu. Cela se produit lorsque la barre de navigation n'est pas translucide ou lorsque l'image d'arrière-plan est définie.

Si vous définissez simplement contentInsetAdjustmentBehavior sur .jamais, les encarts de contenu ne seront pas définis correctement sur iPhone X, Par exemple le contenu irait dans la zone inférieure, sous les barres de défilement.

Il faut faire deux choses:
1. empêcher l'animation de scrollView sur push / pop
2. conserver .comportement automatique car il est nécessaire pour iPhone X. Sans cela, par exemple dans portrait, le contenu ira en dessous de la barre de défilement inférieure.

Nouvelle solution simple: dans XIB: ajoutez simplement UIView au - dessus de votre vue principale avec top, leading et trailing to superview et height mis à 0. Vous n'avez pas besoin de le connecter à d'autres sous-vues ou quoi que ce soit.

Vieille solution:

Remarque: Si vous utilisez UIScrollView en mode paysage, il ne définit toujours pas correctement les encarts horizontaux (un autre bug?), donc vous devez épingler scrollView avant / arrière vers safeAreaInsets dans IB.

Note 2: La Solution ci-dessous a également un problème que si tableView défile vers le bas, et que vous poussez le contrôleur et que vous revenez, il ne sera plus en bas.

override func viewDidLoad()
{
    super.viewDidLoad()

    // This parts gets rid of animation when pushing
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidDisappear(_ animated: Bool)
{
    super.viewDidDisappear(animated)
    // This parts gets rid of animation when popping
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .never
    }
}

override func viewDidAppear(_ animated: Bool)
{
    super.viewDidAppear(animated)
    // This parts sets correct behaviour(insets are correct on iPhone X)
    if #available(iOS 11, *)
    {
        self.tableView.contentInsetAdjustmentBehavior = .automatic
    }
}
3
répondu El Horrible 2017-12-11 08:43:02

Je peux reproduire le bug pour iOS 11.1 mais il semble que le bug soit corrigé depuis iOS 11.2. Voir http://openradar.appspot.com/34465226

2
répondu Linda 2017-12-11 15:35:05

De plus, si vous utilisez la barre d'onglets, l'encart de contenu inférieur de la vue collection sera égal à zéro. Pour cela, mettez ci-dessous le code dans viewDidAppear:

if #available(iOS 11, *) {
    tableView.contentInset = self.collectionView.safeAreaInsets
}
1
répondu hasankose 2017-10-03 11:13:38

Voici comment j'ai réussi à résoudre ce problème tout en permettant à iOS 11 de définir automatiquement les encarts. Je suis à l'aide de UITableViewController.

  • sélectionnez "étendre les bords sous les barres supérieures" et "étendre les bords sous les barres opaques" dans votre contrôleur de vue dans storyboard (ou par programmation). Les encarts de zone de sécurité empêcheront votre vue de passer sous la barre supérieure.
  • cochez le bouton "encarts à Zone de sécurité" sur la vue de votre table dans votre storyboard. (ou tableView.insetsContentViewsToSafeArea = true) - Cela pourrait ne pas être nécessaire, mais c'est ce que j'ai fait.
  • définissez le comportement de réglage de l'encart de contenu sur "Axes de défilement" (ou tableView.contentInsetAdjustmentBehavior = .scrollableAxes) - .always pourrait aussi fonctionner mais je n'ai pas testé.

Une autre chose à essayer si tout le reste échoue:

Remplacer viewSafeAreaInsetsDidChange UIViewController méthode pour obtenir la vue de table pour forcer à définir les encarts de la vue de défilement sur les encarts de zone de sécurité. Ceci est en conjonction avec le paramètre "jamais" dans la réponse de Maggy.

- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    self.tableView.contentInset = self.view.safeAreaInsets;
}

Remarque: self.tableView et self.view devrait être la même chose pour UITableViewController

1
répondu Santa Claus 2017-10-28 03:09:00

Dans mon cas, cela a fonctionné (mettez-le dans viewDidLoad):

self.navigationController.navigationBar.translucent = YES;
1
répondu nemissm 2017-11-12 09:17:04

Veuillez vous assurer avec le code ci-dessus, ajoutez le code supplémentaire comme suit. Il a résolu le problème

override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
     tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) // print(thisUISBTV.adjustedContentInset) 
}
0
répondu Basavaraj Kalaghatagi 2017-10-01 18:37:41

Supprimer ce travail de code pour moi

self.edgesForExtendedLayout = UIRectEdgeNone
0
répondu weiminghuaa 2017-11-07 03:09:42