Puis-je désactiver la mise en page automatique pour une sous-vue spécifique au moment de l'exécution?

104

J'ai une vue qui doit avoir son cadre manipulé par programme - c'est une sorte de vue de document qui s'enroule sur son contenu qui est ensuite fait défiler et zoomé autour d'une vue supervisée en manipulant l'origine du cadre. Autolayout se bat avec cela au moment de l'exécution.

La désactivation complète de la mise en page automatique semble un peu difficile car elle pourrait raisonnablement être utilisée pour gérer la mise en page des autres vues. Il semble que je pourrais souhaiter une sorte de "contrainte nulle".

terriblemoire
la source

Réponses:

168

J'ai eu le même problème. Mais je l'ai résolu.
Oui, vous pouvez désactiver la mise en page automatique au moment de l'exécution pour un UIViewélément spécifique , au lieu de le désactiver pour l'ensemble du xib ou du storyboard défini par défaut dans Xcode 4.3 et versions ultérieures.

Réglez translatesAutoresizingMaskIntoConstraintssur YES, avant de définir le cadre de votre sous-vue:

self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
Muhammad Aamir Ali
la source
2
Cela semble exagéré pour certains cas plus compliqués avec beaucoup de vues. Pour quelque chose d'aussi simple que cela, tout va bien.
esh
@MuhammadAamirALi supprimer la sous-vue, puis l'ajouter à nouveau peut diminuer les performances.Pouvons-nous archiver une meilleure solution?
Nhat Dinh
2
@DinhNhat j'ai clarifié la réponse. Il n'est pas nécessaire de supprimer et de rajouter la sous-vue.
Leandros
5
Il me montre un avertissement: "Impossible de satisfaire simultanément les contraintes."
NSPratik
1
Vous avez sauvé ma journée ... traduitAutoresizingMaskIntoConstraints
Tintenklecks
50

J'ai eu un problème similaire où la mise en page automatique remplaçait certains de mes paramètres de trame au moment de l'exécution (j'avais une vue dynamique qui, dans certains cas, poussait un nouveau contrôleur de vue ... pousser puis appuyer sur Retour réinitialiserait la vue initiale).

J'ai contourné ce problème en insérant mon code de manipulation dans viewDidLayoutSubviewsmon View Controller. Cela semble être appelé après l'appel de la contrainte mojo, mais avant viewDidAppear, donc l'utilisateur n'est pas le plus sage.

jmstone617
la source
1
Ne fonctionne pas pour self.navigationItem.titleView. Ne respecte toujours pas le changement de cadre.
Henrik Erlandsson
1
Si vous essayez de muck avec le cadre d'une vue de titre, je le placerais dans une vue de conteneur et ajouterais la vue de conteneur en tant que vue personnalisée de navigationItem.
jmstone617
2
Cela a fonctionné pour moi aussi. J'avais perdu 2h: 22m à me cogner la tête contre le mur proverbial avant de découvrir cette solution de contournement.
TMc
Merci mec. Je suis dans mon deuxième jour aux prises avec ce problème et maintenant cela fonctionne!
apostolov
28

Peut-être que simplement définir translatesAutoresizingMaskIntoConstraintssur YES(et ne pas ajouter de contraintes supplémentaires affectant cette vue) vous permettra de définir le cadre sans lutter contre le système de disposition automatique.

Jon Hull
la source
17

Dans iOS 8, vous pouvez définir un NSLayoutConstraint pour qu'il soit actif ou non. Donc, si j'utilise le constructeur d'interface, j'ajoute toutes mes contraintes à un OutletCollection puis j'active ou je désactive en utilisant:

NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)

L'application particulière pour laquelle je l'utilise ici a des contraintes différentes en mode portrait et paysage et j'active / désactive en fonction de la rotation de l'appareil. Cela signifie que je peux créer des modifications de mise en page complexes dans le générateur d'interface pour les deux orientations, et continuer à utiliser la mise en page automatique sans le code de mise en page automatique détaillé.

Ou vous pouvez activer / désactiver en utilisant removeConstraints et addConstraints.

bandejapaisa
la source
Désolé d'avoir détourné une question aussi ancienne, mais puis-je vous demander comment vous avez réussi à ajouter des contraintes de mise en page pour différentes mises en page en premier lieu? Je n'arrive pas à trouver une option dans le générateur d'interface pour activer / désactiver une contrainte. Ou avez-vous simplement ajouté des contraintes pour les deux mises en page et ignoré simplement le constructeur d'interface se plaignant de contraintes non valides (écrasantes)?
Malte
Eh bien, vous pouvez le faire en utilisant des classes de taille: developer.apple.com/library/ios/recipes/... , mais je ne pouvais pas le faire de cette façon car je supportais également iOS 7 et les classes de taille ne supportent pas entièrement iOS 7 Je l'ai fait en abaissant la priorité de la contrainte conflictuelle. Pas idéal, mais cela empêche l'avertissement. Je pense que c'est comme ça que je l'ai fait de toute façon ....
bandejapaisa
9

Je ne sais pas si cela aidera quelqu'un d'autre, mais j'ai écrit une catégorie pour rendre cela pratique parce que je me retrouve à faire cela beaucoup.

UIView + DisableAutolayoutTemporately.h

#import <UIKit/UIKit.h>

@interface UIView (DisableAutolayoutTemporarily)

// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;

@end

UIView + DisableAutolayoutTemporately.m

#import "UIView+DisableAutoResizeTemporarily.h"
@implementation UIView (DisableAutoResizeTemporarily)

- (void)resizeWithBlock:(void (^)(UIView * view))block
{
    UIView *superview = self.superview;
    [self removeFromSuperview];
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    __weak UIView *weakSelf = self;
    block(weakSelf);
    [superview addSubview:self];
}

@end

Je l'utilise comme ça:

[cell.argumentLabel resizeWithBlock:^(UIView *view) {
    [view setFrame:frame];
}];

J'espère que ça aide.

MichaelNowden
la source
Brillant ! J'ai utilisé une version modifiée de votre code pour écrire une simple fonction "hideControl" pour n'importe quel UIView. Il définit fondamentalement la hauteur d'un UIView sur 0, mais, de manière cruciale, il utilise votre code pour que AutoLayout le gère correctement (contrairement à l'utilisation de "someView.hidden = TRUE"). Ainsi, les contrôles qui apparaissaient sous le contrôle masqué et qui avaient un espacement vertical lié à celui-ci, se déplaçaient maintenant vers le haut sur l'écran pour combler l'espace, là où la vue masquée apparaissait auparavant.
Mike Gledhill
6

Vous pouvez définir le translatesAutoresizingMaskIntoConstraintstype Boolean, Valeur Oui dans les attributs d'exécution définis par l'utilisateur de l'UIView que vous voulez dans le xib / storyboard.

renaun
la source
2
  • Projet ouvert en 4.5
  • Sélectionnez le storyboard
  • Ouvrez l'inspecteur de fichiers
  • Sous Document Interface Builder, décochez "Utiliser la mise en page automatique"

Vous pouvez diviser en plusieurs storyboards si vous souhaitez utiliser la disposition automatique pour certaines vues.

Mike Bobbitt
la source
10
Cela désactive la mise en page automatique pour l'ensemble du storyboard / nib. Ce que je cherchais était un moyen (idéalement programmatique) d'avoir des sous-vues particulières dans un storyboard / nib ne pas utiliser la mise en page automatique tout en laissant le reste faire tout ce que le storyboard / nib spécifié.
terriblememory
Vous pouvez utiliser plusieurs storyboards et appeler simplement ceux avec / sans mise en page automatique si nécessaire: // Initialisez le contrôleur de stockage et de vue détaillée pour l'affichage UIStoryboard * sb = [UIStoryboard storyboardWithName: @ Bundle "Storyboard": [NSBundle mainBundle]]; DetailViewController * dvController = [sb instantiateViewControllerWithIdentifier: entry.viewName];
Mike Bobbitt
1

Pour moi, cela fonctionnait pour créer la sous-vue par programme, dans mon cas, la mise en page automatique perturbait une vue dont je devais faire pivoter autour de son centre, mais une fois que j'ai créé cette vue par programme, cela fonctionnait.

Andrespch
la source
1

À mon avis, j'avais une étiquette et un texte. L'étiquette avait un geste panoramique. L'étiquette se déplace bien pendant le glissement. Mais lorsque j'utilise le clavier de la zone de texte, l'étiquette réinitialise sa position à l'emplacement d'origine défini dans la disposition automatique. Le problème a été résolu lorsque j'ai ajouté ce qui suit dans Swift pour l'étiquette. J'ai ajouté ceci dans viewWillAppear mais il peut être ajouté à peu près partout où vous avez accès au champ cible.

self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Grand d
la source
0

Cela m'est arrivé dans un projet sans storyboards ni fichiers xib. Tous les codes à 100%. J'avais une bannière publicitaire en bas et je voulais que les limites de vue s'arrêtent à la bannière publicitaire. La vue se redimensionnerait automatiquement après le chargement. J'ai essayé toutes les résolutions de cette page mais aucune n'a fonctionné.

J'ai fini par créer une vue secondaire avec la hauteur raccourcie et je l'ai placée dans la vue principale du contrôleur. Ensuite, tout mon contenu est entré dans la vue secondaire. Cela a résolu le problème très facilement sans rien faire qui semblait aller à contre-courant.

Je pense que si vous voulez une vue qui n'est pas la taille normale qui remplit la fenêtre, vous devriez utiliser une vue secondaire pour cela.

RandallTo
la source
0

J'ai rencontré un scénario similaire, dans lequel j'ai rejoint un projet initié avec la mise en page automatique, mais j'avais besoin de faire des ajustements dynamiques sur plusieurs vues. Voici ce qui a fonctionné pour moi:

  1. N'ayez PAS de vues ou de composants présentés dans le générateur d'interface.

  2. Ajoutez vos vues de manière purement programmatique en commençant par alloc / init et en définissant leurs cadres de manière appropriée.

  3. Terminé.

Ouaip.
la source
0

Au lieu de désactiver la mise en page automatique, je calculerais simplement la nouvelle contrainte avec le cadre que vous remplacez. Cela me semble être la manière appropriée. Si vous ajustez des composants qui reposent sur des contraintes, ajustez-les en conséquence.

Par exemple, si vous avez une contrainte verticale de 0 entre deux vues (myView et otherView) et que vous avez un mouvement de panoramique ou quelque chose qui ajuste la hauteur de myView, vous pouvez recalculer la contrainte avec les valeurs ajustées.

self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
Myles Caley
la source
0

Pour ceux d'entre vous qui utilisent la mise en page automatique, veuillez consulter ma solution ici . Vous @IBOutletdevez définir les contraintes que vous souhaitez ajuster, puis modifier leurs constantes.

Mike
la source
-16

s'il s'agit d'un fichier xib:

  1. sélectionnez le fichier .xib
  2. sélectionnez le "Propriétaire du fichier"
  3. montrer les utilitaires
  4. cliquez sur: "Inspecteur de fichiers"
  5. Sous "Document de création d'interface", désactivez: "Utiliser la mise en page automatique"
Alish
la source
1
Non, cela désactive la mise en page automatique pour tout le xib. Ce que je cherchais, c'est un moyen de supprimer une seule sous-vue particulière du système de mise en page automatique.
terriblememory