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>>
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]];
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.
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)]];
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
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.
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...
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.