J'ai une seule fenêtre avec une seule vue personnalisée et je veux que la vue personnalisée soit redimensionnée avec la fenêtre afin qu'elle la remplisse entièrement à tout moment. Si j'écris:
NSView *contentView = [self.window contentView];
CustomView *customView = [[CustomView alloc] initWithFrame:[contentView bounds]];
[contentView addSubview:customView];
[contentView addConstraint:
[NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[contentView addConstraint:
[NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
Ensuite, la fenêtre ne me permet pas de la redimensionner.
Si j'ajoute:
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
Ensuite, la vue personnalisée n'apparaît pas (drawRect:
semble ne jamais être appelé). J'ai essayé différentes manières (dont le format visuel @"|[customview]|"
) mais je rencontre toujours les mêmes problèmes. Je sais que cela pourrait être fait avec l'ancien système de redimensionnement automatique, avec:
[customView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
mais je veux utiliser le système Cocoa Auto Layout, et je veux l'utiliser pour des cas plus compliqués (comme plusieurs vues personnalisées qui remplissent toujours la fenêtre).
Quelqu'un sait-il ce qui ne va pas et comment utiliser le système de disposition automatique pour obtenir le résultat souhaité?
Avec la disposition automatique, il existe (au moins) trois façons possibles de contraindre une vue afin qu'elle occupe la vue de contenu de la fenêtre entière, en la redimensionnant le cas échéant.
NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
[contentView addSubview:customView];
NSDictionary *views = NSDictionaryOfVariableBindings(customView);
[contentView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|"
options:0
metrics:nil
views:views]];
[contentView addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|"
options:0
metrics:nil
views:views]];
(cela devrait être équivalent au format visuel ci-dessus)
+ (void)addEdgeConstraint:(NSLayoutAttribute)Edge superview:(NSView *)superview subview:(NSView *)subview {
[superview addConstraint:[NSLayoutConstraint constraintWithItem:subview
attribute:Edge
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:Edge
multiplier:1
constant:0]];
}
et
NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
[contentView addSubview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeLeft superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeRight superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeTop superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeBottom superview:contentView subview:customView];
NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
[contentView addSubview:customView];
[contentView addConstraint:
[NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:0]];
[contentView addConstraint:
[NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeHeight
multiplier:1
constant:0]];
La troisième approche est celle indiquée dans la question et elle peut ne pas fonctionner s'il y a d'autres contraintes. Par exemple, sans:
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
le masque de redimensionnement automatique d'origine est également appliqué, ce qui entraîne le comportement décrit dans la question: la fenêtre n'est pas redimensionnée.
Comme mentionné par Regexident, vous pouvez utiliser:
[_window visualizeConstraints:[contentView constraints]];
pour déboguer la disposition automatique. Cela vaut également la peine de vérifier la sortie de la console.
@ La réponse de Bavarious est bonne, je vais juste ajouter quelques éléments supplémentaires.
Il est vraiment important d'apprendre à utiliser le support de débogage intégré! Comme avec beaucoup de développement, il n'est pas réaliste d'espérer que vous obtiendrez toujours tout ce qu'il faut sur le premier coup. C'était une préoccupation majeure avec la disposition automatique, nous avons donc mis beaucoup d'efforts dans le débogage. Étapes, brièvement:
Habituellement, le type de question que vous publiez (mes trucs ne fonctionnent pas!) Ne sera pas suffisant pour que les gens disent ce qui ne va pas, c'est l'une des raisons pour lesquelles il est important d'utiliser les trucs de débogage. Voir la vidéo de la session WWDC 2011 (gratuite pour tous) et les documents pour en savoir plus.
Buuuuut, je peux dire ce qui s'est mal passé cette fois. :-) Avant de désactiver translatesAutoresizingMaskIntoConstraints, vous étiez plus contraint que vous ne le souhaitiez - la largeur et la hauteur de votre vue étaient également fixes, c'est pourquoi la fenêtre ne pouvait pas être redimensionnée. APRÈS l'avoir désactivé, vous aviez une disposition ambiguë, car vous n'aviez fixé votre vue sur rien! Vous aviez dit à quel point il devait être grand (identique à la vue d'ensemble), mais pas où il était censé être.
Ken
Cocoa Frameworks, auteur principal de la mise en page automatique
Vous pouvez créer des contraintes avec des ancres de mise en page au format très facile à lire:
code Swift 2
func fit(childView: UIView, parentView: UIView) {
childView.translatesAutoresizingMaskIntoConstraints = false
childView.topAnchor.constraintEqualToAnchor(parentView.topAnchor).active = true
childView.leadingAnchor.constraintEqualToAnchor(parentView.leadingAnchor).active = true
childView.trailingAnchor.constraintEqualToAnchor(parentView.trailingAnchor).active = true
childView.bottomAnchor.constraintEqualToAnchor(parentView.bottomAnchor).active = true
}
Utilisation:
parrentView.addSubview(childView)
fit(childView, parentView: parrentView)
J'ai découvert que -drawRect: ne sera pas appelé dans le cas où le rectangle de trame est 0,0,0,0. Des contraintes indésirables semblent faire en sorte que le cadre devienne 0,0,0,0.