web-dev-qa-db-fra.com

En centrant le X de la sous-vue dans l'autolayout, jette "non préparé pour la contrainte"

J'ai une sous-classe UIView personnalisée en cours d'initialisation via un nib.

Dans -awakeFromNib, Je crée une sous-vue et tente de la centrer dans son aperçu.

[self setInteralView: [[UIView alloc] init]];
[[self internalView] addConstraint: [NSLayoutConstraint constraintWithItem: [self internalView]
                                                                 attribute: NSLayoutAttributeCenterX
                                                                 relatedBy: NSLayoutRelationEqual
                                                                    toItem: self
                                                                 attribute: NSLayoutAttributeCenterX
                                                                multiplier: 1
                                                                  constant: 0]];

Cela casse et provoque la sortie suivante:

2013-08-11 17:58:29.628 MyApp[32414:a0b] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
    When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2013-08-11 17:58:29.630 MyApp[32414:a0b] View hierarchy unprepared for constraint.
    Constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
    Container hierarchy: 
<UIView: 0xc132a40; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0xc132bc0>>
    View not found in container hierarchy: <MyView: 0xc1315a0; frame = (-128 -118; 576 804); layer = <CALayer: 0xc131710>>
    That view's superview: <UIView: 0xc131a70; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0xc131b50>>
79
Patrick Perini

Lorsque l'erreur indique, vous devez ajouter la contrainte à une vue de sorte que les vues impliquées dans la contrainte soient la vue à laquelle vous l'ajoutez ou une sous-vue de cette vue. Dans le cas de votre code ci-dessus, vous devriez ajouter cette contrainte à self, plutôt que [self internalView]. La raison pour laquelle cela ne fonctionne pas tel qu'écrit est l'une des vues impliquées dans la contrainte (self) n'est pas dans la hiérarchie des vues si vous ne tenez compte que de [self internalView] et plus bas).

Pour plus de détails, voir le section de discussion de la documentation sur le addConstraint: méthode.

Voici votre ligne de code, corrigée comme je le suggère:

UIView* internalView = [[UIView alloc] initWithFrame:CGRectZero];
internalView.translatesAutoresizingMaskIntoConstraints = NO;
[self setInternalView:internalView];

[self addConstraint: [NSLayoutConstraint constraintWithItem: [self internalMapView]
                                         attribute: NSLayoutAttributeCenterX
                                         relatedBy: NSLayoutRelationEqual
                                         toItem: self
                                         attribute: NSLayoutAttributeCenterX
                                         multiplier: 1
                                         constant: 0]];
92
Charles A.

Pour les autres qui viennent ici: j'ai eu cette erreur, car j'ai ajouté les contraintes avant d'ajouter les sous-vues à la hiérarchie.

115
Jannie Theunissen

Réponse courte : échange vue parent et enfant.
En supposant que self est la vue parente:

  • mauvais: [subview addConstraint [NSLayoutConstraint constraintWithItem:self...

  • bien: [self addConstraint [NSLayoutConstraint constraintWithItem:subview...


rapide

subview.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
    "H:|-0-[subview]-0-|",
    options: .DirectionLeadingToTrailing,
    metrics: nil,
    views: ["subview":subview]))

Obj-C

[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addConstraints:[NSLayoutConstraint
                      constraintsWithVisualFormat:@"H:|-0-[subview]-0-|"
                      options:NSLayoutFormatDirectionLeadingToTrailing
                      metrics:nil
                      views:NSDictionaryOfVariableBindings(subview)]];
36
SwiftArchitect

Conseils supplémentaires:

J'ai une application nouvellement développée qui fonctionne correctement sur iOS7 mais une erreur se produit sur iOS8 "La hiérarchie des vues n'est pas préparée pour la contrainte".

Lire un autre article a déclaré que les (sous) vues doivent être ajoutés avant de créer des contraintes. Je l'ai fait mais j'ai toujours l'erreur.

Puis j'ai compris que je devrais créer des contraintes sous - (void) viewDidAppear au lieu de viewDidLoad

10
Kevin

C'est une vieille question, mais je tiens à souligner cette ligne de la documentation:

Lors du développement pour iOS 8.0 ou version ultérieure, définissez la propriété isActive de la contrainte sur true au lieu d'appeler directement la méthode addConstraint (_ :). La propriété isActive ajoute et supprime automatiquement la contrainte de la vue correcte.

À tout le moins, cela supprimera un point d'échec puisque vous n'avez plus à vous soucier d'appeler addConstraint sur la mauvaise vue.

5
WongWray

Dans mon cas, le problème a été résolu en utilisant la vue racine comme conteneur de contraintes au lieu de la vue créée.

Je veux dire, utiliser à l'intérieur de viewController

view.addConstraints([leftConstraintImage, topConstraintImage]) au lieu de imageView.addConstraints...

2
Vyacheslav

Comme @CharlesA le souligne dans sa réponse, le problème est que la vue que vous ajoutez ne se trouve pas dans la hiérarchie appropriée. Sa réponse est bonne, mais je vais donner quelques détails pour un cas d'utilisation particulier qui a causé ce problème pour moi:

Cela arrivait lorsque j'essayais d'ajouter des contraintes à une vue dont j'avais instancié le contrôleur de vue à l'aide de instantiateViewControllerWithIdentifier. Pour résoudre le problème, j'ai utilisé [childViewController didMoveToParentViewController:self]. Cela a ajouté la vue dans la hiérarchie de vues référencée par ma contrainte.

1
benvolioT