web-dev-qa-db-fra.com

UIStackView - Problèmes de contrainte de présentation lors du masquage des vues de pile

Mon application a 2 écrans:

  1. TableViewVC (pas de vues de pile ici) 

  2. DetailVC (toutes les vues de pile imbriquées ici; veuillez consulter le lien pour l'image: Image imbriquée de StackViews ) - Veuillez noter qu'il existe des étiquettes et des images dans ces vues de pile. 

Lorsque vous appuyez sur une cellule de la vue table, les informations de TableViewVC sont transmises à DetailVC. Le problème est que masque les vues UIStackViews spécifiques dans DetailVC. Je souhaite que seulement 2 vues de pile parmi les différentes vues de DetailVC soient masquées dès le chargement de la vue. Donc j'écris ce code dans le DetailVC pour accomplir ceci:

override func viewDidLoad() {
    super.viewDidLoad()

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true
}

Tout a l'air génial, mais Xcode donne beaucoup d'avertissements uniquement à runtime Storyboard n'émet aucun avertissement lorsque l'application n'est pas en cours d'exécution. S'il vous plaît voir le lien pour l'image des erreurs: Image des erreurs

Fondamentalement, il y a beaucoup d'erreurs de connexion UISV, de masquage UISV, d'espacement UISV. Ces erreurs disparaissent si je cache les mêmes vues de pile dans viewDidAppear, mais il y a alors un éclair de la substance qui était censée être cachée, puis il se cache. L'utilisateur voit brièvement la vue puis se cache, ce qui n'est pas bien. 

Désolé de ne pas pouvoir publier de photos au lieu de liens, je ne peux toujours pas le faire. 

Des suggestions sur la façon de résoudre ce problème? Ceci est pour une application que je veux réellement lancer sur l'App Store - c'est ma première fois alors toute aide serait géniale!

Edition/Mise à jour 1:

J'ai trouvé un petit problème avec ce code que j'ai mis dans le deuxième écran appelé DetailVC:

// Function I use to delay hiding of views
func delay(delay: Double, closure: ()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

// Hide the 2 stack views after 0.0001 seconds of screen loading
override func awakeFromNib() {
    delay(0.001) { () -> () in
        self.summaryStackView.hidden = true
        self.combinedStackView.hidden = true
    }
}

// Update view screen elements after 0.1 seconds in viewWillAppear
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    delay(0.1) { () -> () in
        self.nameLabel.text = "John"
    }
}

Cela supprime complètement les avertissements concernant les contraintes de mise en page de Xcode.

Ce n'est pas encore parfait, car parfois, je vois un aperçu des points de vue censés être cachés - ils clignotent très rapidement sur l'écran puis disparaissent. Cela arrive si vite cependant. 

Des suggestions quant à pourquoi cela supprime les avertissements? En outre, toutes les suggestions sur la façon d'améliorer ceci fonctionnent-elles parfaitement??? Merci!

22
JEL

Avez-vous essayé cela, appeler le super après vos changements?

override func viewWillAppear() {

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true

    super.viewWillAppear()
}
0
adamek

J'ai eu le même problème et je l'ai résolu en donnant la priorité à 999 aux contraintes de hauteur de mes vues initialement masquées.

 enter image description here

Le problème est que votre stackview applique une contrainte de hauteur de 0 sur votre vue masquée, ce qui est en conflit avec votre autre contrainte de hauteur. C'était le message d'erreur:

Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>",
    "<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>"
)

Donner à votre contrainte de hauteur une priorité inférieure résout ce problème.

80
Raphael

Il s'agit d'un problème connu lié au masquage des vues de pile imbriquées.

Il y a essentiellement 3 solutions à ce problème:

  1. Définissez l'espacement sur 0, mais vous devrez alors vous rappeler la valeur précédente.
  2. Appelez innerStackView.removeFromSuperview(), mais vous devrez alors vous rappeler où insérer la vue de pile.
  3. Enveloppez la vue de pile dans UIView avec au moins une contrainte de 999. Par exemple. En haut, en tête, à la traîne à 1000, en bas à 999.

La 3ème option est la meilleure à mon avis. Pour plus d'informations sur ce problème, pourquoi cela se produit-il, les différentes solutions et comment implémenter la solution 3, voir ma réponse à une question similaire .

23
Senseful

Vous pouvez utiliser les propriétés removeArrangedSubview et removeFromSuperview de UIStackView.

En Objective-C:

 [self.topStackView removeArrangedSubview:self.summaryStackView];
 [self.summaryStackView removeFromSuperview];

 [self.topStackView removeArrangedSubview:self.combinedStackView];
 [self.combinedStackView removeFromSuperview];

De la documentation Apple UIStackView: ( https://developer.Apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//Apple_ref/occ/instm/UIStackView/removeArrangedSubview :)

La vue de pile met automatiquement à jour sa mise en page chaque fois que des vues sont ajoutées, supprimées ou insérées dans le tableau arrangSubviews.

  • removeArrangedSubview: cette méthode supprime la vue fournie du tableau de la pile de la pile. La position et la taille de la vue ne seront plus gérées par la vue de pile. Cependant, cette méthode ne supprime pas la vue fournie du tableau de sous-vues de la pile; par conséquent, la vue est toujours affichée dans la hiérarchie des vues.

Pour empêcher la vue d’apparaître à l’écran après l’appel de la méthode removeArrangedSubview: de la pile, supprimez explicitement la vue du tableau de sous-vues en appelant la méthode removeFromSuperview de la vue ou définissez la propriété masquée de la vue sur YES.

8
Dinesh

Lorsque UIViewStack est masqué, les contraintes générées automatiquement par UIStackView émettent de nombreux avertissements de masquage UISV, d'espacement UISV et de connexion UISV-canvas, si la propriété d'espacement d'UIStackView a une valeur autre que zéro.

Cela n'a pas beaucoup de sens, c'est presque certainement un bug du framework. La solution de contournement que j’utilise consiste à définir l’espacement à zéro lors du masquage du composant.

if hideStackView {
    myStackView.hidden = true
    myStackView.spacing = CGFloat(0)
} else {
    myStackView.hidden = false
    myStackView.spacing = CGFloat(8)
}
2

J'ai constaté que UIStackViews imbriqué présente ce comportement si vous définissez la propriété masquée dans «Générateur d'interface». Ma solution consistait à définir tout ce qui n'était pas caché dans «Interface Builder» et à masquer certains éléments dans viewWillAppear de manière sélective.

1
Jacob Jennings

Je l'ai corrigé en mettant les commandes de masquage dans traitCollectionDidChange.

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    self.item.hidden = true
}
1
aqubi

Donc, cela ne peut aider que 0,000001% des utilisateurs, mais peut-être s'agit-il d'un problème lié aux clips.

Je me suis heurté récemment à cette situation lorsque je travaillais avec UICollectionViewCell. J'ai oublié de vérifier les clips jusqu'à la limite que je traitais en tant que vue de contenu. Lorsque vous créez une UITableViewCell dans IB, elle configure par défaut une vue de contenu avec des clips.

Le fait est que, selon votre situation, vous pourrez peut-être obtenir l'effet que vous souhaitez en utilisant des cadres et des découpages.

1
Joe Susnick

J'ai déplacé tout le code UIStackView.hidden de viewDidLoad à viewDidAppear et le problème des contraintes brisées a disparu. Dans mon cas, toutes les contraintes conflictuelles étaient générées automatiquement, donc aucun moyen d’ajuster les priorités.

J'ai aussi utilisé ce code pour le rendre plus joli:

UIView.animateWithDuration(0.5) {
    self.deliveryGroup.hidden = self.shipVia != "1"
}

MODIFIER:

Nous avions également besoin du code suivant pour que cela ne se reproduise plus lors de la rotation du périphérique:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    self.deliveryGroup.hidden = false

    coordinator.animateAlongsideTransition(nil) {
    context in
        self.deliveryGroup.hidden = self.shipVia != "1"
    }
}
1
tigaris

Cette erreur ne concerne pas la dissimulation, mais des contraintes ambiguës. Vous ne devez avoir aucune contrainte ambiguë dans votre vue. Si vous les ajoutez par programme, vous devez comprendre exactement les contraintes que vous ajoutez et leur interaction. ne sont pas des erreurs de contrainte ou des avertissements.

UPD: Vous avez une structure de vues assez complexe ici. Sans voir les contraintes, il est difficile de dire ce qui ne va pas. Cependant, je suggérerais de vous construire une hiérarchie de vues en ajoutant progressivement des vues une par une et en vous assurant qu'il n'y a pas d'avertissements de conception/exécution. La vue défilement peut ajouter un autre niveau de complexité si vous ne la gérez pas correctement. Découvrez comment utiliser les contraintes avec une vue de défilement ... Tous les autres hacks de synchronisation ne sont pas une solution.

0
Davyd

Je l'ai fait en stockant toutes les vues cachées de UIStackView imbriqué dans un tableau et en les supprimant de la vue d'ensemble et des sous-vues organisées. Quand je voulais qu'ils apparaissent à nouveau, j'ai parcouru le tableau et les ai rajoutés. C'était la première étape.

La deuxième étape consiste à supprimer les vues de la vue UIStackView imbriquée de la vue d'ensemble, mais le parent UIStackView n'a toujours pas ajusté sa hauteur. Vous pouvez résoudre ce problème en supprimant le UIStackView imbriqué et en l'ajoutant tout de suite après:

UIStackView *myStackView;
NSUInteger positionOfMyStackView = [parentStackView indexOfObject:myStackView];
[parentStackView removeArrangedSubview:myStackView];
[myStackView removeFromSuperview];
[parentStackView insertArrangedSubview:myStackView atIndex:positionOfMyStackView];
0
sp00ky

Mettez vos commandes hide dans viewWillLayoutSubviews() {}

0
Tim