Uso de layout automático en una vista personalizada donde las limitaciones dependen del marco.

Estoy escribiendo una vista personalizada que se inicializa mediante progtwigción. updateConstraints para agregar todas las restricciones necesarias para esta vista. :

 - (void)updateConstraints { [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]]; [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeTop multiplier:1 constant:0]]; [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.superview attribute:NSLayoutAttributeBottom multiplier:1 constant:0]]; // some more constraints, you get the point self.bottomSpacingConstraint = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-(0.2 * CGRectGetHeight(self.bounds))]; [self addConstraint:self.bottomSpacingConstraint]; [super updateConstraints]; } 

El problema es que self.bounds devuelve el equivalente de CGRectZero . Hice mi investigación y de acuerdo con este artículo objc.io , se espera que el marco no se establezca hasta que se layoutSubviews . También menciona

Para obligar al sistema a actualizar el layout de un tree de vista inmediatamente, puede llamar a layoutIfNeeded / layoutSubtreeIfNeeded (en iOS y OS X respectivamente). Esto puede ser útil si los siguientes pasos se basan en el marco de las vistas actualizado.

Sin embargo, cuando agrego

 [self setNeedsLayout]; [self layoutIfNeeded]; 

justo antes de configurar self.bottomSpacingConstraint en updateConstraints , todavía obtengo un CGRectZero para el marco. Según el artículo objc.io (y esta respuesta SO ), estos methods deberían activar el layout y actualizar el marco.

¿Alguien puede aclarar cómo hacer que todo esto funcione? Me interesa la solución, así como una explicación de las causas de los methods relacionados con el layout (por ejemplo, parece que cambiar la constante de una restricción existente en layoutSubviews hace que se llame setNeedsUpdateConstraints , lo que desencadena updateConstraints y provoca restricciones para agregarse varias veces).

Estoy bastante seguro de que no se puede, o no, llamar a layoutIfNeeded desde updateConstraints . La actualización de las restricciones se encuentra en una parte anterior del ciclo de layout, por lo que no creo que tenga el efecto que está buscando.

En su caso, la solución sería comprobar la propiedad constant de la restricción dependiente de marco en layoutSubviews, y si necesita actualización, actualícela allí o llame a setNeedsUpdateConstraints (tenga cuidado al hacer loops).

Dijo que actualizar la restricción desencadena otra llamada a updateConstraints , esto es cierto, y creo que está updateConstraints mal la updateConstraints , es para actualizar restricciones basadas en cambios en el contenido de su vista. Solo debería agregar esas restricciones si aún no existen.