Impossible de déplacer la position Y de UILabel avec Autolayout "on" en vue

Je dois manquer quelque chose de terriblement évident ici, mais cela a été un problème qui m'a frustré pour JOURS.

Dans un projet iOS sur xcode 4.5, j'ai plusieurs labels dans un XIB, l'un sur l'autre, dans un UIScrollView qui occupe un UIView . Chaque label est aussi large que la vue, et chacune est d'environ 20 px au-dessus de la suivante. Parfois, l'une des labels ne contient aucune information, elle est donc définie sur invisible, et les labels situées en dessous sont censées se déplacer pour occuper l'espace vide.

Le problème est que, si la command autolayout est désactivée sur la vue, les labels se déplacent exactement comme elles le devraient, bien que l' UIScrollView ne défile plus. Si elle est activée , les labels ne bougent pas du tout, quoi qu'il arrive.

Voici le code … J'utilise simplement une fonction rapide pour déplacer chaque label de la hauteur de l'label invisible.

 [self moveObjectBy: self.festNameLabel moveByY:-(yearsLabel.frame.size.height-2)]; // this just quickly moves a label. - (void)moveObjectBy:(UIView *)lbl moveByY:(int)byHeight { CGRect newFrame = lbl.frame; NSLog(@"%f, %d", newFrame.origin.y, byHeight); newFrame.origin.y += byHeight; //yearsLabel.frame.size.height; lbl.frame = newFrame; } 

Quand il est exécuté, le NSLog montre que Y a bougé, mais il ne bouge pas à l'écran. Je suis sûr que cela a à voir avec la contrainte d'espace vertical, mais il ne me laissera pas supprimer la contrainte, et il ne me laissera pas le changer pour autre chose que l'espace du haut de la vue. Comme je l'ai dit, je suis sûr de manquer quelque chose, mais j'ai épuisé tout ce que je sais faire …

Si vous avez juste une label qui pourrait être cachée, vous pouvez déplacer celles qui se trouvent en dessous, avec ce qui suit:

  -(void)contract { self.label2.hidden = YES; self.con2To1.constant = -34; } 

L'label supérieure a une contrainte en haut de la vue de défilement, et toutes les autres labels ont des contraintes de distance verticales de 20 points par rapport à celles situées au-dessus et en dessous d'elles. Dans cet exemple, je cache label2. Les labels ont toutes 34 points de haut, donc changer la constante de contrainte de 20 à -34 déplace l'label maintenant cachée juste au-dessus de celle au-dessus.

Pour utiliser cette méthode avec plusieurs labels qui peuvent être masquées, vous devez disposer d'une sortie pour chacune des labels que vous souhaitez masquer, et de sa contrainte à l'label ci-dessus. Vous pouvez en fait le faire sans les sorties aux contraintes, mais je ne sais pas si ce serait aussi robuste (il est possible qu'il choisisse la mauvaise contrainte). J'ai été capable de faire la même chose en bouclant les contraintes pour find celle qui va avec une label particulière, et c'est celle qui est en haut de cette label:

 -(void)hideLabel:(UILabel *) label { label.hidden = YES; for (NSLayoutConstraint *con in self.scroller.constraints) { if (con.firstItem == label && con.firstAtsortingbute == NSLayoutAtsortingbuteTop) { con.constant = -34; } } } 

La même méthode peut être modifiée pour utiliser une animation si vous le souhaitez: l'extrait suivant fait disparaître l'label que vous souhaitez masquer tout en animant le déplacement de toutes les labels inférieures.

  -(void)hideLabel:(UILabel *) label { for (NSLayoutConstraint *con in self.scroller.constraints) { if (con.firstItem == label && con.firstAtsortingbute == NSLayoutAtsortingbuteTop) { con.constant = -34; [UIView animateWithDuration:.5 animations:^{ label.alpha = 0; [self.scroller layoutIfNeeded]; }]; } } } 

Avec l'autolayout en place, vous ne pouvez pas définir de frameworks sur les sous-vues. Au mieux, cela fonctionnera temporairement jusqu'à ce que la passe de layout suivante ait eu lieu. À ce moment, la disposition définie par vos contraintes sera rétablie.

Ce que vous avez à faire est de modifier les contraintes qui sont en place sur la vue. Dans votre cas, il serait judicieux d'avoir une contrainte de broche spécifique sur chaque label. Vous pouvez ensuite créer des points de vente pour chacune de ces contraintes. Pour une label de hauteur nulle, vous devez alors définir la constante sur la contrainte correspondante à zéro. Les labels ci-dessous vont ensuite se déplacer vers le haut.

Selon l'label que vous retirez, cela peut vous laisser avec un écart double-large. Vous pouvez supprimer ceci en modifiant les contraintes d'espacement, ou vous pouvez vous débarrasser complètement des contraintes d'espacement et juste avoir chaque label un peu plus grande, mais juste l'un à côté de l'autre – le contenu de l'label sera centré verticalement.

Le message principal est que vous ne définissez pas de frameworks. Vous modifiez, ajoutez et / ou supprimez des contraintes à la place.

Si vous voulez le faire en swift:

 for item in self.view.constraints { if item.firstItem .isKindOfClass(UITextField) { let newField = item.firstItem as! UITextField if newField == answerTextField && item.firstAtsortingbute == NSLayoutAtsortingbute.Top { item.constant = answerFrame.origin.y self.view .layoutIfNeeded() } } if item.firstItem .isKindOfClass(UIButton) { let newField = item.firstItem as! UIButton if newField == submitButton && item.firstAtsortingbute == NSLayoutAtsortingbute.Top { item.constant = submitFrame.origin.y self.view .layoutIfNeeded() } } }