web-dev-qa-db-fra.com

Supprimer les contraintes de disposition automatique pour un objet spécifique

J'ai un UIImageView intégré dans un UIView. Toute mon application utilise AutoLayout, mais je souhaite supprimer constraints pour le UIImageView. Xcode ne me permettra pas de supprimer constraints, existe-t-il un moyen de les désactiver pour un objet spécifique, de les définir sur zéro, quelque chose?

50
Eric

Je conviens que la mise en page automatique de Xcode est horrible à utiliser si vous voulez quelque chose de particulier ...

Ce que j'utilise pour supprimer les contraintes par programmation:

[detailsPhotoView removeConstraints:detailsPhotoView.constraints];
89
Thomas Decaux

Dans XCode 5, il existe une option lors de la modification des contraintes "Supprimer au moment de la construction". Si cela est activé, la contrainte sera automatiquement supprimée pendant l'exécution. L'option est là pour garder Interface Builder heureux si vous ne voulez pas de contraintes particulières.

25
Christian

Il y a deux problèmes distincts ici:

  1. Comment utiliser Xcode pour configurer un UIImageView sans contraintes
  2. Comment autoriser le panoramique et/ou le redimensionnement de UIImageView lorsque sa disposition est gérée par des contraintes.

En ce qui concerne (1), jturton est correct. Tant que vous avez activé la présentation automatique dans Xcode, Xcode garantira/exigera que les contraintes soient suffisantes pour déterminer de manière unique la taille et l'emplacement de votre vue.

Si vous n'avez pas spécifié manuellement suffisamment de contraintes dans Xcode (via les "contraintes de l'utilisateur" qui apparaissent en bleu dans l'inspecteur du modèle), Xcode ajoutera de nouvelles contraintes qu'il devine (qui apparaissent en violet) jusqu'à ce qu'il y ait suffisamment de contraintes pour déterminer la disposition.

Si UIImageView n'avait aucune contrainte, sa disposition ne serait pas déterminée, vous ne pouvez donc pas la configurer dans Xcode. Pour résoudre ce problème, vous devez utiliser Xcode pour configurer IBOutlets sur toutes les contraintes que vous souhaitez supprimer, puis dans awakeFromNib: de votre UIView ou dans viewDidLoad de votre UIViewController :. Vous supprimez manuellement les contraintes en appelant removeConstraints :.

Cependant, la disposition de votre UIImageView est maintenant sous-déterminée. Donc, à ce stade, vous voudrez ajouter manuellement de nouvelles contraintes qui vous permettront de déplacer et de redimensionner UIImageView, ce qui nous amène à question (2).

En ce qui concerne (2), comment redimensionner et déplacer une vue dont la mise en page est déterminée par des contraintes, la solution consiste à configurer les dispositifs de reconnaissance de geste comme d'habitude pour détecter les gestes de pincement et de panoramique, mais au lieu de ces dispositifs de reconnaissance de geste appelant setFrame: pour modifier la vue, ils doivent modifier le paramètre constant d'une NSLayoutConstraint qui détermine le cadre de UIImageView, puis appeler layoutIfNeeded :, ce qui obligera le système de présentation à traduire immédiatement cette contrainte modifiée dans un nouveau cadre.

Supposons, par exemple, que vous souhaitiez manipuler UIImageView avec un ensemble de contraintes de présentation très similaires aux appels setFrame habituels. Dans ce cas, après avoir supprimé les contraintes configurées par Xcode, vous pouvez ajouter à la vue des contraintes qui spécifient sa largeur, sa hauteur et son espace en haut et à gauche de la vue d'ensemble. Ensuite, le gestionnaire d’actions de votre outil de reconnaissance des mouvements de panoramique mettra simplement à jour le paramètre constant du dispositif de reconnaissance des mouvements de stimulation, et votre outil de reconnaissance des gestes de pincement pourra simplement mettre à jour le paramètre de constante des contraintes de hauteur et de largeur.

Une autre façon de faire (2), qui est la même sous le capot mais qui pourrait être plus facile en pratique, consiste à définir translatesAutoresizingMaskIntoConstraints=YES. Cela fera deux choses. Le système de présentation automatique générera automatiquement des contraintes dans la vue d'ensemble de la vue en fonction du masque autoresizing de la vue. Deuxième point crucial! - le système de mise en page traduira automatiquement les appels à setFrame: en modifications de ces contraintes.

8
algal

Vous ne pouvez pas ne pas avoir de contraintes - vous devez avoir suffisamment de contraintes en place pour dimensionner et positionner sans ambiguïté chaque vue.

Vous pouvez créer une vue redimensionnable à l'aide de l'option Autolayout.

Par exemple, dans votre cas, vous pouvez créer des contraintes de positionnement, par exemple, épingler le centre de la vue de l’image horizontalement et verticalement au centre de sa vue d’ensemble.

Vous pouvez également créer des contraintes de taille, horizontalement et verticalement. Voir ma réponse ici pour savoir comment faire cela. Créez des points de vente pour ces deux contraintes (si vous utilisez le générateur d'interface). Vous pouvez avoir des contraintes de hauteur et de largeur d'un nombre spécifique, ou utiliser le multiplicateur pour créer un rapport de format fixe.

En réponse aux gestes de pincement, vous pouvez régler le .constant Propriétés des deux contraintes de taille et appelez setNeedsLayout. Cela redimensionnera votre vue tout en gardant son centre épinglé.

Si vous suivez la suggestion de rapport hauteur/largeur ci-dessus, redimensionner une vue à l'aide de contraintes est en réalité beaucoup plus simple que de définir le cadre.

6
jrturton

tu peux appeler

[yourElement removeFromSuperview];

et ensuite appeler

[yourSuperview addSubview:yourElement];

pour supprimer toutes les contraintes de yourElement et les rajouter à la vue.

Il est à noter que si vous procédez comme indiqué ci-dessus dans une catégorie ou une extension UIView, vous devez enregistrer une référence au superview de la vue avant de la supprimer:

var theSuperview = self.superview
self.removeFromSuperview()
theSuperview?.addSubview(self)

Vous pourriez également avoir besoin de rendre votre élément fort au lieu de faible, car le fait de retirer Superview risquerait de vous faire perdre une référence.

5
Adam Johns

Si vous souhaitez simplement supprimer une vue d'une hiérarchie, appelez simplement [theView removeFromSuperview]. Toute contrainte l’affectant sera également supprimée.

Cependant, vous pouvez aussi parfois souhaiter rétablir une vue, après l'avoir temporairement supprimée.

Pour ce faire, j'utilise la catégorie suivante sur UIView. Il passe de la vue v dans la hiérarchie des vues à une vue conteneur ultime c (généralement la vue racine de votre contrôleur de vue) et supprime les contraintes externes à v. Ce sont des contraintes qui sont frères de v, plutôt que des contraintes qui affectent uniquement les enfants de v. Vous pouvez masquer v.

-(NSArray*) stealExternalConstraintsUpToView: (UIView*) superview
{
    NSMutableArray *const constraints = [NSMutableArray new];

    UIView *searchView = self;
    while(searchView.superview && searchView!= superview)
    {
        searchView = searchView.superview;

        NSArray *const affectingConstraints =
        [searchView.constraints filteredArrayUsingPredicate:
         [NSPredicate predicateWithBlock:^BOOL(NSLayoutConstraint *constraint, NSDictionary *bindings)
          {
              return constraint.firstItem == self || constraint.secondItem == self;
          }]];

        [searchView removeConstraints: affectingConstraints];
        [constraints addObjectsFromArray: affectingConstraints];
    }

    return constraints;
}

La méthode retransmet les contraintes supprimées dans un tableau que vous pouvez conserver quelque part afin de pouvoir ultérieurement rajouter les contraintes.

Utilisez-le un peu comme ça…

NSArray *const removedConstraints = [viewToHide stealExternalConstraintsUpToView: self.view];
[viewToHide setHidden: YES];

Et plus tard, rétablissez les contraintes.

A partir d'iOS 8, vous n'avez pas besoin de penser aux contraintes. Il suffit d'utiliser ceci…

[NSLayoutConstraint activateConstraints: removedConstraints];
[viewToHide setHidden: NO];

Avec les versions antérieures d'iOS, vous n'avez pas besoin de réfléchir sérieusement à l'endroit où ajouter les contraintes. Jetez ensuite dans le contrôleur self.view. À condition que les contraintes soient en une vue supérieure de toutes les vues qu’elles affectent, elles fonctionneront.

[self.view addConstraints: removedConstraints];
[viewToHide setHidden: NO];
4
Benjohn