Implementar intrinsicContentSize correctamente para tamaños que dependen del layout interno resuelto.

Tengo una solución que parece estar funcionando, pero quiero asegurarme de que sea seguro y use la herramienta según lo previsto. Puedo destilar mi problema a este escenario: tengo una UIView que contiene múltiples UILabels, astackdos verticalmente. Cada label se puede rellenar con text arbitrario que envuelve y expande la label verticalmente. Las restricciones de layout automático para astackr las tags dentro de la vista son triviales. Lo que me gustaría hacer es que UIView comunique a su propietario su altura preferida (la altura de la vista debe ajustarse a todas las tags) a través de intrinsicContentSize . Sin embargo, el layout interno debe resolverse antes de que pueda devolver la altura adecuada. Mi entendimiento es que se garantiza que el solucionador esté completo después de regresar de [super layoutSubviews] , esto es lo que estoy haciendo:

 - (void)layoutSubviews { [super layoutSubviews]; // solver's complete, now we can measure? [self invalidateIntrinsicContentSize]; } 

Mi implementación intrinsicContentSize hace reference al marco de la última label para calcular la altura. Todo parece funcionar para mi caso actual, pero me pone nervioso. Parece ser que el solucionador solicita el tamaño de contenido intrínseco de la vista actual mientras está distribuyendo sus componentes internos. No voy a entrar en detalles, pero me encontré con un caso en el que este patrón giraba en un bucle infinito. Pude solucionar este problema modificando parte del código de layout, esto no inspiró confianza.

¿Hay una mejor manera de hacer esto? Esto parece algo común que quiero hacer y cuando empecé a trabajar en el problema pensé que esto era para lo que era intrinsicContentSize. Las implementaciones de intrinsicContentSize que he visto siempre han sido triviales: tamaño codificado para una dimensión, o la medición de una sola vista que no depende de un layout interno resuelto.

Tenga en count que no puedo usar las tags con los methods NSString sizeWith... porque el layout interno es demasiado complejo.

Tenga en count que exploré usar systemLayoutSizeFittingSize: pero llamar a esto desde los resultados intrinsicContentSize en un bucle infinito.

¡Cualquier respuesta será apreciada! ¡Gracias por adelantado!

Me gustaría actualizar este hilo y cerrar esta pregunta: creo que todavía hay valor aquí para otras personas que recién comienzan con AutoLayout y que podrían tener un malentendido similar. Es importante comprender el verdadero propósito de intrinsicContentSize; no es así como las vistas típicas comunican su tamaño preferido a sus vistas principales. Si una vista usa AutoLayout para distribuir a sus hijos, entonces usará las restricciones que definen su layout interno para informar a su padre acerca de su tamaño; específicamente, serán las restricciones que relacionan las vistas secundarias a su padre que van a ayudar a definir el tamaño de los padres Esta es realmente la parte de AutoLayout que es a la vez mágica y frustrante: es la sum de todas estas restricciones (tanto internas como externas a su vista) que dan como resultado el layout. El tamaño intrínseco solo es necesario en casos en los que su vista no utiliza AutoLayout para definir su tamaño (como el caso clásico de UILabel o UIImageView).

Creo que los primeros errores / inconsistencias de iOS relacionados con el text multilínea fueron lo que me condujo a la intrinsicContentSize. El text multilínea todavía no es perfecto, pero con suerte mejor en iOS10.

Aquí está la solución que se me ocurrió para este problema. Si desea proporcionar un NSView intrinsicContentSize de un NSView que encapsula otras instancias de NSView , existen dos posibilidades. Cualquiera de las subvenciones tiene valores intrinsicContentSize Contenido y puede trabajar con ellos, de lo contrario, hay al less un valor NSViewNoInstrinsicMetric alguna parte y debe confiar en el resultado de la disposition de esas subvenciones para calcular su Contenido intrinsicContentSize .

En el segundo caso, su contenido intrinsicContentSize depende de los valores de marco de sus subvistas y debe reactjsr a cualquier cambio en esos fotogtwigs, al igual que una label reactjs a cualquier cambio en el text que contiene. Puede hacerlo utilizando el NSViewFrameDidChangeNotification . Así es como lo hice en mi subclass NSView personalizada:

 - (void)didAddSubview:(NSView *)subview { [super didAddSubview:subview]; subview.postsFrameChangedNotifications = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subviewFrameDidChange:) name:NSViewFrameDidChangeNotification object:subview]; [self setNeedsUpdateConstraints:YES]; [self invalidateIntrinsicContentSize]; } - (void)willRemoveSubview:(NSView *)subview { [super willRemoveSubview:subview]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewFrameDidChangeNotification object:subview]; [self setNeedsUpdateConstraints:YES]; [self invalidateIntrinsicContentSize]; } - (void)subviewFrameDidChange:(NSNotification*)notif { [self invalidateIntrinsicContentSize]; }