Ne devrait-il pas y avoir un moyen de redimensionner le cadre d’un UIView après avoir ajouté des sous-vues afin que le cadre corresponde à la taille requirejse pour inclure toutes les sous-vues? Si vos sous-vues sont ajoutées dynamicment, comment pouvez-vous déterminer la taille du cadre de la vue du conteneur? Cela ne fonctionne pas:
[myView sizeToFit];
Check-out Avoir du mal à faire en sorte que UIView sizeToFit fasse quelque chose de significatif
L’essentiel est que sizeToFit
est destiné à être sizeToFit
par des sous-classes et ne fait rien dans UIView. Il fait des choses pour UILabel
, car il remplace sizeThatFits:
qui est appelé par sizeToFit
Vous pouvez également append le code suivant pour calculer la position des sous-vues.
[myView resizeToFitSubviews]
UIViewUtils.h
#import @interface UIView (UIView_Expanded) -(void)resizeToFitSubviews; @end
UIViewUtils.m
#import "UIViewUtils.h" @implementation UIView (UIView_Expanded) -(void)resizeToFitSubviews { float w = 0; float h = 0; for (UIView *v in [self subviews]) { float fw = v.frame.origin.x + v.frame.size.width; float fh = v.frame.origin.y + v.frame.size.height; w = MAX(fw, w); h = MAX(fh, h); } [self setFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, w, h)]; } @end
J’avais besoin d’ajuster les sous-vues à un point d’origine négatif, et CGRectUnion
est la manière ObjC de le faire, honnêtement, comme quelqu’un l’a mentionné dans les commentaires. Tout d’abord, voyons comment cela fonctionne:
Comme vous pouvez le voir ci-dessous, nous supposons que certaines sous-vues sont situées à l’extérieur, nous devons donc faire deux choses pour que cela soit beau, sans affecter le positionnement des sous-vues:
Une image vaut mieux que mille mots.
Le code vaut un milliard de mots. Voici la solution:
@interface UIView (UIView_Expanded) - (void)resizeToFitSubviews; @end @implementation UIView (UIView_Expanded) - (void)resizeToFitSubviews { // 1 - calculate size CGRect r = CGRectZero; for (UIView *v in [self subviews]) { r = CGRectUnion(r, v.frame); } // 2 - move all subviews inside CGPoint fix = r.origin; for (UIView *v in [self subviews]) { v.frame = CGRectOffset(v.frame, -fix.x, -fix.y); } // 3 - move frame to negate the previous movement CGRect newFrame = CGRectOffset(self.frame, fix.x, fix.y); newFrame.size = r.size; [self setFrame:newFrame]; } @end
J’ai pensé que ce serait amusant d’écrire dans Swift 2.0. J’avais raison!
extension UIView { func resizeToFitSubviews() { let subviewsRect = subviews.reduce(CGRect.zero) { $0.union($1.frame) } let fix = subviewsRect.origin subviews.forEach { $0.frame.offsetInPlace(dx: -fix.x, dy: -fix.y) } frame.offsetInPlace(dx: fix.x, dy: fix.y) frame.size = subviewsRect.size } }
Et la preuve du terrain de jeu:
Notez que visualAidView
ne bouge pas et vous aide à voir comment la superview
redimensionne tout en conservant les positions des sous-vues.
let canvas = UIView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) canvas.backgroundColor = UIColor.whiteColor() let visualAidView = UIView(frame: CGRect(x: 5, y: 5, width: 70, height: 70)) visualAidView.backgroundColor = UIColor(white: 0.8, alpha: 1) canvas.addSubview(visualAidView) let superview = UIView(frame: CGRect(x: 15, y: 5, width: 50, height: 50)) superview.backgroundColor = UIColor.purpleColor() superview.clipsToBounds = false canvas.addSubview(superview) [ { let view = UIView(frame: CGRect(x: -10, y: 0, width: 15, height: 15)) view.backgroundColor = UIColor.greenColor() return view }(), { let view = UIView(frame: CGRect(x: -10, y: 40, width: 35, height: 15)) view.backgroundColor = UIColor.cyanColor() return view }(), { let view = UIView(frame: CGRect(x: 45, y: 40, width: 15, height: 30)) view.backgroundColor = UIColor.redColor() return view }(), ].forEach { superview.addSubview($0) }
Il semblerait que la réponse de Kenny à la question ci-dessus pointe vers la bonne solution dans la question référencée , mais peut avoir enlevé le mauvais concept. La référence de classe UIView
suggère UIView
un système permettant de rendre sizeToFit
pertinent pour vos vues personnalisées.
sizeThatFits
, pas sizeToFit
Votre UIView
personnalisé doit remplacer sizeThatFits
pour renvoyer “une nouvelle taille qui correspond aux sous-vues du récepteur”, mais vous souhaitez calculer ceci. Vous pouvez même utiliser les calculs mathématiques d’ une autre réponse pour déterminer votre nouvelle taille (mais sans recréer le système sizeToFit
intégré).
Une fois que sizeThatFits
renvoie des numéros pertinents pour son état, les appels à sizeToFit
sur vos vues personnalisées sizeToFit
les redimensionnements attendus.
sizeThatFits
fonctionne Sans un remplacement, sizeThatFits
renvoie simplement le paramètre de taille transmis (par défaut à self.bounds.size
pour les appels de sizeToFit
. Bien que je ne dispose que de deux sources sur le problème, il semble que la taille transmise ne soit pas visible). comme une demande ssortingcte.
[
sizeThatFits
] renvoie la taille “la plus appropriée” pour le contrôle qui correspond aux contraintes qui lui sont transmises. La méthode peut (accentuer les leurs) décider d’ignorer les contraintes si elles ne peuvent pas être satisfaites.
Mis à jour la réponse de @ Mazyod à Swift 3.0, a fonctionné comme un charme!
extension UIView { func resizeToFitSubviews() { let subviewsRect = subviews.reduce(CGRect.zero) { $0.union($1.frame) } let fix = subviewsRect.origin subviews.forEach { $0.frame.offsetBy(dx: -fix.x, dy: -fix.y) } frame.offsetBy(dx: fix.x, dy: fix.y) frame.size = subviewsRect.size } }
Ancienne question, mais vous pourriez aussi le faire avec une fonction récursive.
Vous voudrez peut-être une solution qui fonctionne toujours, peu importe le nombre de sous-vues et de sous-vues, …
Mise à jour: Le morceau de code précédent avait seulement une fonction de lecture, maintenant aussi un setter.
extension UIView { func setCGRectUnionWithSubviews() { frame = getCGRectUnionWithNestedSubviews(subviews: subviews, frame: frame) fixPositionOfSubviews(subviews, frame: frame) } func getCGRectUnionWithSubviews() -> CGRect { return getCGRectUnionWithNestedSubviews(subviews: subviews, frame: frame) } private func getCGRectUnionWithNestedSubviews(subviews subviews_I: [UIView], frame frame_I: CGRect) -> CGRect { var rectUnion : CGRect = frame_I for subview in subviews_I { rectUnion = CGRectUnion(rectUnion, getCGRectUnionWithNestedSubviews(subviews: subview.subviews, frame: subview.frame)) } return rectUnion } private func fixPositionOfSubviews(subviews: [UIView], frame frame_I: CGRect) { let frameFix : CGPoint = frame_I.origin for subview in subviews { subview.frame = CGRectOffset(subview.frame, -frameFix.x, -frameFix.y) } } }