El marco de la vista del contenedor se establece en CGRectZero cuando se usa el layout automático programático

Tengo una subclass UIView que será una información sobre herramientas que puede aparecer en la parte inferior de cualquier controller de vista para mostrar un post de aviso / error / post de éxito / etc. La vista de información sobre herramientas tiene dos subvistas: una UILabel en el lado izquierdo y una UIView en el lado derecho, que puede ser cualquier cosa (pero a menudo se usa como un UIButton ).

TooltipView.h

 @interface TooltipView : UIView @property (nonatomic, readonly) UILabel *textLabel; @property (nonatomic) UIView *rightView; 

TooltipView.m

 static CGFloat const kSubviewToSuperviewSpacing = 7.0f; static CGFloat const kTextLabelToRightViewHorizontalSpacing = 7.0f; @implementation TooltipView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _textLabel = [[UILabel alloc] init]; _textLabel.numberOfLines = 0; [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; [self addSubview:_textLabel]; } return self; } - (void)setRightView:(UIView *)rightView { if (_rightView != rightView) { _rightView = rightView; [self addSubview:_rightView]; [self setNeedsDisplay]; } } - (BOOL)translatesAutoresizingMaskIntoConstraints { return NO; } - (void)updateConstraints { self.didUpdateConstraints = YES; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0f constant:kSubviewToSuperviewSpacing]]; NSMutableDictionary *metricsDictionary = [@{@"subviewToSuperviewSpacing": @(kSubviewToSuperviewSpacing)} mutableCopy]; NSMutableDictionary *viewsDictionary = [@{@"textLabel": self.textLabel} mutableCopy]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-subviewToSuperviewSpacing-[textLabel]-subviewToSuperviewSpacing-|" options:0 metrics:metricsDictionary views:viewsDictionary]]; if (self.rightView) { metricsDictionary[@"textLabelToRightViewHorizontalSpacing"] = @(kTextLabelToRightViewHorizontalSpacing); viewsDictionary[@"rightView"] = self.rightView; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-subviewToSuperviewSpacing-[rightView]-subviewToSuperviewSpacing-|" options:0 metrics:metricsDictionary views:viewsDictionary]]; [self addConstraint:[NSLayoutConstraint constraintWithItem:self.rightView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:kSubviewToSuperviewSpacing]]; } [super updateConstraints]; } 

También tengo un controller de vista para probar esto con un UILabel como rightView . Es subclasss UIViewController , y su único método loadView :

 - (void)loadView { TooltipView *tooltipView = [[TooltipView alloc] initWithFrame:CGRectZero]; tooltipView.textLabel.text = @"Test 1"; UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectZero]; testLabel.text = @"Hello there"; [testLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; tooltipView.rightView = testLabel; self.view = tooltipView; 

}

Finalmente, en el controller de vista donde quiero mostrar una información sobre herramientas, agrego el TooltipViewController como un controller de vista secundario. Eventualmente, esto será desencadenado por algún evento, pero para propósitos de testing, esto se agrega a viewWillAppear:

 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.aViewController = [[TooltipViewController alloc] init]; self.aViewController.view.backgroundColor = [UIColor whiteColor]; [self addChildViewController:self.aViewController]; [self.view addSubview:self.aViewController.view]; [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:@{@"view": self.aViewController.view}]]; [self.aViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:self.aViewController.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:150.0f]]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.aViewController.view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; [self.aViewController didMoveToParentViewController:self]; } 

Sin embargo, en time de ejecución, los frameworks de textLabel y rightView parecen estar configurados correctamente, pero el marco de tooltipView se establece en CGRectZero , y ninguna de las tres vistas aparece en la pantalla.

¡Gracias por adelantado!

EDITAR

Incluso he intentado quitar textLabel y rightView completo, así que solo una vista UIV simple con restricciones de altura, de background, de background y de final. Nada es ambiguo, pero el marco de la vista sigue siendo CGRectZero .

Resulta que la solución era simplemente llamar a setTranslatesAutoresizingMaskIntoConstraints en el inicializador de TooltipView lugar de anular el método. Esto provocó que la vista aparezca correctamente. h / t a Aaron Thompson ( https://twitter.com/aaptho/status/612815498661773312 ).

Parece que te falta una restricción relacionada con textLabel y rightView . Al -updateConstraints su implementación -updateConstraints , creo que las restricciones finales pueden expressse mediante:

 V:|-kSubviewToSuperviewSpacing-[textLabel]-kSubviewToSuperviewSpacing-| V:|-kSubviewToSuperviewSpacing-[rightView]-kSubviewToSuperviewSpacing-| H:|-kSubviewToSuperviewSpacing-[textLabel] H:[rightView]-kSubviewToSuperviewSpacing-| 

Si agrega una relación de restricción dentro de usted if (self.rightView) como:

 [self addConstraint:[NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.rightView attribute:NSLayoutAttributeLeading multiplier:1.0f constant: kTextLabelToRightViewHorizontalSpacing]]; 

Y luego agregar y else cláusula:

 [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[textLabel]-subviewToSuperviewSpacing-|" options:0 metrics:metricsDictionary views:viewsDictionary]]; 

Tendrás suficientes restricciones para definir inequívocamente el layout. Eso debería desencadenar el auto-dimensionamiento basado en restricciones cuando se encuentra en la supervisión.

Si eso no funciona, debería revisar el método -intrinsicContentSize y devolver el contenido intrínseco de textLabel y rightView más su relleno. Deberá llamar -invalidateIntrinsicContentSize en -setRightView: para que funcione correctamente.

Como punto menor, no está eliminando ninguna restricción en -updateConstraints , por lo que en un paso de actualización de restricción que llama a esta vista, obtendrá dobles restricciones. Es posible que desee mover parte de la creación de restricción en -init y luego solo agregar / eliminar la relación textLabel y rightView en -updateConstraints según sea necesario.