Imbriquée UIStackViews Cassé Contraintes
J'ai un complexe de vue de la hiérarchie, construit dans Interface Builder, avec imbriqué UIStackViews. J'ai "unsatisfiable contraintes" avis à chaque fois que je cacher certains de mes intérieure stackviews. Je l'ai suivi jusqu'à présent:
(
"<NSLayoutConstraint:0x1396632d0 'UISV-canvas-connection' UIStackView:0x1392c5020.top == UILabel:0x13960cd30'Also available on iBooks'.top>",
"<NSLayoutConstraint:0x139663470 'UISV-canvas-connection' V:[UIButton:0x139554f80]-(0)-| (Names: '|':UIStackView:0x1392c5020 )>",
"<NSLayoutConstraint:0x139552350 'UISV-hiding' V:[UIStackView:0x1392c5020(0)]>",
"<NSLayoutConstraint:0x139663890 'UISV-spacing' V:[UILabel:0x13960cd30'Also available on iBooks']-(8)-[UIButton:0x139554f80]>"
)
Plus précisément, le UISV-spacing
contrainte: lorsque le masquage d'une UIStackView sa forte contrainte obtient un 0 constante, mais qui semble en contradiction avec l'intérieur empilervoir espacement contrainte: elle nécessite de 8 points entre mon Étiquette et Bouton, ce qui est inconciliable avec la clandestinité la contrainte et donc les contraintes de crash.
Est-il un moyen de contourner cela? J'ai essayé de manière récursive en cachant tout l'intérieur StackViews cachés vue de la pile, mais que les résultats dans d'étranges animations où le contenu flotte au-dessus de l'écran, et provoque de graves FPS gouttes de démarrage, alors toujours pas à résoudre le problème.
Vous devez vous connecter pour publier un commentaire.
Idéalement, nous pourrions nous contenter de définir la priorité de la
UISV-spacing
contrainte à une valeur plus faible, mais il ne semble pas être un moyen de le faire. 🙂Je vais avoir du succès réglage de la
spacing
propriété de la imbriquée de la pile des points de vue à 0 avant de se cacher, et la restauration à la valeur correcte après de la rendre visible à nouveau.Je pense faire cela de façon récursive sur imbriquée pile de vue de travail. Vous pouvez stocker la valeur d'origine de la
spacing
propriété dans un dictionnaire et de le restaurer plus tard.Mon projet n'a qu'un seul niveau d'imbrication, donc je suis pas certain que cela entraînerait des problèmes de FPS. Tant que vous n'avez pas d'animer les changements de l'espacement, je ne pense pas que cela créerait trop d'un coup.
C'est un problème connu avec de cacher imbriquée de la pile des points de vue.
Il y a essentiellement 3 solutions à ce problème:
innerStackView.removeFromSuperview()
, mais alors vous aurez besoin de se rappeler où insérer la pile de vue.La 3ème option est la meilleure à mon avis. Pour plus d'informations sur ce problème, pourquoi cela se produit, les différentes solutions, et comment mettre en œuvre la solution 3, voir ma réponse à une question similaire.
J'ai frappé un problème similaire avec UISV-clandestinité. Pour moi, la solution a été de réduire les priorités de mes propres contraintes de Requis (1000) à quelque chose de moins que cela. Lorsque UISV-masquage des contraintes sont ajoutées, elles ont la priorité et les contraintes ne sont plus en conflit.
Donc, vous avez ceci:
Et le problème est que, lors de la première de l'effondrement de l'intérieur de la pile, vous obtenez la mise en page automatique des erreurs:
Le problème, comme vous l'avez remarqué, c'est que l'extérieur de la pile point de vue s'applique à une hauteur = 0 contrainte à l'intérieur de la vue de la pile. Cela entre en conflit avec les 8 points de rembourrage contrainte appliquée par l'intérieur vue de la pile entre ses propres sous-vues. Les deux contraintes ne peuvent pas être satisfaits simultanément.
L'extérieur vue de la pile utilise cette hauteur = 0 contrainte, je crois, car il semble mieux lors de l'animation de la laisser le point de vue interne, être caché, sans rétrécissement de la première.
Il y a une solution simple à cela: d'envelopper l'intérieur vue de la pile dans une plaine
UIView
, et de cacher que le wrapper. Je vais démontrer.Voici la scène de structure pour la version endommagée ci-dessus:
Pour résoudre le problème, sélectionnez l'intérieur vue de la pile. À partir de la barre de menu, choisissez l'Éditeur > Intégrer Dans > Affichage:
Interface Builder crée une largeur de contrainte sur l'emballage de la vue quand je l'ai fait, donc supprimer que la largeur de la contrainte:
Ensuite, créer des contraintes entre les quatre bords de l'enveloppe et l'intérieur de la pile affichage:
À ce stade, la mise en page est correcte au moment de l'exécution, mais l'Interface Builder attire de façon incorrecte. Vous pouvez résoudre le problème en définissant la verticale serrant les priorités de l'intérieur de la pile, les enfants de plus. J'ai mis à 800:
Nous n'avons pas réellement fixe le unsatisfiable contraindre problème à ce stade. Pour ce faire, trouvez le fond de la contrainte que vous venez de créer et de définir des priorités de moins que prévu. Nous allons changer de 800:
Enfin, vous avez sans doute eu une prise de courant dans votre vue-contrôleur connecté à l'intérieur de la pile de vue, parce que vous étaient en train de changer son
hidden
de la propriété. Changer cette prise pour connecter le wrapper de vue au lieu de l'intérieur de la vue de la pile. Si votre prise est de typeUIStackView
, vous aurez besoin de la modifier pourUIView
. Le mien était déjà de typeUIView
, alors j'ai juste rebranché dans le storyboard:Maintenant, lorsque vous mettez de l'emballage de la vue
hidden
propriété, la vue de la pile apparaît à l'effondrement, sans unsatisfiable contrainte de mises en garde. Il ressemble presque à l'identique, donc je ne vais pas la peine de poster un autre GIF de l'application en cours d'exécution.Vous pouvez trouver mon projet de test dans ce dépôt github.
Une autre approche
Essayez d'éviter imbriquée UIStackViews. Je les aime et construire presque tout avec eux. Mais comme je l'ai reconnu qu'ils secrètement ajouter des contraintes j'essaie de ne les utiliser au plus haut niveau et non-imbriquées, si possible. De cette façon, je peux préciser le 2ème plus haute priorité
.defaultHigh
à l'espacement de la contrainte qui permet de résoudre mes avertissements.Cette priorité est juste assez pour éviter la plupart des problèmes d'implantation.
Bien sûr, vous devez spécifier un plus de contraintes, mais de cette façon, vous avez le plein contrôle d'eux et de les faire à votre disposition de l'affichage explicite.
Ici de la mise en œuvre de Senseful la suggestion #3 écrit comme Swift 3 classe à l'aide de SnapKit contraintes. J'ai aussi essayé en substituant les propriétés, mais n'a jamais pu fonctionner sans mise en garde, donc je vais rester avec emballage UIStackView: