¿Qué es NSLayoutConstraint “UIView-Encapsulated-Layout-Height” y cómo debo hacer para que se vuelva a calcular limpiamente?

Tengo un UITableView corriendo bajo iOS 8 y estoy usando alturas de celda automáticas de restricciones en un guión gráfico.

Una de mis celdas contiene una sola UITextView y necesito que se contraiga y expanda según la entrada del usuario: toque para reducir / expandir el texto.

Estoy haciendo esto agregando una restricción de tiempo de ejecución a la vista de texto y cambiando la constante en la restricción en respuesta a los eventos del usuario:

 -(void)collapse:(BOOL)collapse; { _collapsed = collapse; if(collapse) [_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0 else [_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]]; [self setNeedsUpdateConstraints]; } 

Cuando hago esto, lo tableView en tableView actualizaciones de tableView y llamo a [tableView setNeedsUpdateConstraints] :

 [tableView beginUpdates]; [_briefCell collapse:!_showFullBriefText]; [tableView setNeedsUpdateConstraints]; // I have also tried // [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop]; // with exactly the same results. [tableView endUpdates]; 

Cuando hago esto, mi celda se expande (y se anima mientras lo hace) pero recibo una advertencia de restricciones:

 2014-07-31 13:29:51.792 OneFlatEarth[5505:730175] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "", "" ) Will attempt to recover by breaking constraint  

388 es mi altura calculada, las otras restricciones en el UITextView son mías de Xcode / IB.

El último me molesta, supongo que UIView-Encapsulated-Layout-Height es la altura calculada de la celda cuando se procesa por primera vez (configuré que mi altura de UITextView es> = 70.0) sin embargo, no parece derecho a que esta restricción derivada invalide un cnstraint de usuario actualizado.

Peor aún, aunque el código de diseño dice que está tratando de romper mi restricción de altura, no lo hace; continúa recalculando la altura de la celda y todo dibuja como me gustaría.

Entonces, ¿qué es NSLayoutConstraint UIView-Encapsulated-Layout-Height (Supongo que es la altura calculada para el tamaño de celda automático) y cómo debo hacer para obligarlo a volver a calcular limpiamente?

Intente bajar la prioridad de _collapsedtextHeightConstraint a 999. De esta forma, el sistema suministrado con la UIView-Encapsulated-Layout-Height siempre tiene prioridad.

Se basa en lo que devuelve en -tableView:heightForRowAtIndexPath: Asegúrese de devolver el valor correcto y su propia restricción y la generada debe ser la misma. La prioridad más baja para su propia restricción solo se necesita temporalmente para evitar conflictos mientras las animaciones de colapso / expansión están en vuelo.

Tengo un escenario similar: una vista de tabla con una celda de fila, en la que hay algunas líneas de objetos UILabel. Estoy usando iOS 8 y autolayout.

Cuando giré obtuve el sistema incorrecto de altura de fila calculada (43.5 es mucho menor que la altura real). Parece que:

 "" 

No es solo una advertencia. El diseño de mi celda de vista de tabla es terrible: todo el texto se superpone en una línea de texto.

Me sorprende que la siguiente línea “solucione” mi problema mágicamente (autolayout no se queja y obtengo lo que esperaba en la pantalla):

 myTableView.estimatedRowHeight = 2.0; // any number but 2.0 is the smallest one that works 

con o sin esta línea:

 myTableView.rowHeight = UITableViewAutomaticDimension; // by itself this line only doesn't help fix my specific problem 

Pude conseguir que la advertencia desapareciera especificando una prioridad en uno de los valores en la restricción que los mensajes de advertencia dicen que tuvo que romperse (debajo de "Will attempt to recover by breaking constraint" ). Parece que mientras establezca la prioridad en algo mayor que 49 , la advertencia desaparece.

Para mí, esto significaba cambiar mi restricción que la advertencia decía que intentaba romper:

@"V:|[contentLabel]-[quoteeLabel]|"

a:

@"V:|-0@500-[contentLabel]-[quoteeLabel]|"

De hecho, puedo agregar una prioridad a cualquiera de los elementos de esa restricción y funcionará. No parece importar cuál. Mis celdas terminan en la altura correcta y la advertencia no se muestra. Roger, para su ejemplo, intente agregar @500 justo después de la restricción de 388 valores de altura (por ejemplo, 388@500 ).

No estoy del todo seguro de por qué esto funciona, pero he investigado un poco. En la enumeración NSLayoutPriority , parece que el nivel de prioridad NSLayoutPriorityFittingSizeCompression es 50 . La documentación para ese nivel de prioridad dice:

Cuando envía un mensaje apropiado a una vista, se calcula el tamaño más pequeño que sea lo suficientemente grande para el contenido de la vista. Este es el nivel de prioridad con el que la vista quiere ser lo más pequeña posible en ese cálculo. Es bastante bajo En general, no es apropiado establecer una restricción exactamente en esta prioridad. Quieres ser más alto o más bajo.

La documentación del mensaje fittingSize referenciado dice:

El tamaño mínimo de la vista que satisface las restricciones que contiene. (solo lectura)

AppKit establece esta propiedad con el mejor tamaño disponible para la vista, teniendo en cuenta todas las restricciones que mantiene y sus subvistas y satisfaciendo una preferencia para hacer que la vista sea lo más pequeña posible. Los valores de tamaño en esta propiedad nunca son negativos.

No he profundizado más allá de eso, pero parece tener sentido que esto tenga algo que ver con el lugar donde reside el problema.

En lugar de informar a la vista de tabla para actualizar sus restricciones, intente volver a cargar la celda:

 [tableView beginUpdates]; [_briefCell collapse:!_showFullBriefText]; [tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone]; [tableView endUpdates]; 

UIView-Encapsulated-Layout-Height es probablemente la altura que la vista de tabla calcula para la celda durante la carga inicial, según las restricciones de la celda en ese momento.

Otra posibilidad:

Si usa el diseño automático para calcular la altura de la celda (height de ContentView, la mayoría de las veces como se muestra a continuación), y si tiene uitableview separator, necesita agregar la altura del separador, para volver a la altura de la celda. Una vez que obtenga la altura correcta, no tendrá esa advertencia de autodiseño.

 - (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell { [sizingCell setNeedsLayout]; [sizingCell layoutIfNeeded]; CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; return size.height; // should + 1 here if my uitableviewseparatorstyle is not none } 

Pude resolver este error quitando un elemento espurio cell.layoutIfNeeded() que tenía en el tableView mi tableView . ¯ \ _ (ツ) _ / ¯

Al dimensionar la vista de texto para adaptarla a su contenido y actualizar la constante de restricción de altura a la altura resultante, se corrigió el UIView-Encapsulated-Layout-Height la UIView-Encapsulated-Layout-Height para mí, por ejemplo:

 [self.textView sizeToFit]; self.textViewHeightConstraint.constant = self.textView.frame.size.height; 

Después de pasar algunas horas rascándome la cabeza con este error, finalmente encontré una solución que funcionó para mí. Mi principal problema era que tenía múltiples plumillas registradas para diferentes tipos de células, pero un tipo de celda específicamente tenía diferentes tamaños (no todas las instancias de esa celda iban a tener el mismo tamaño). así que el problema surgió cuando la mesa de trabajo intentaba dequeuear una celda de ese tipo y tenía una altura diferente. Lo solucioné estableciendo

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

cada vez que la célula tenía sus datos para calcular su tamaño. Me imagino que puede estar en

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

algo como

cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

¡Espero que esto ayude!

TableView obtiene altura para la celda en indexPath desde delegado. luego obtenga la celda de cellForRowAtIndexPath :

 top (10@1000) cell bottom (0@1000) 

if cell.contentView.height: 0 // <-> (UIView-Encapsulated-Layout-Height: 0 @ 1000) top (10 @ 1000) en conflicto con (UIView-Encapsulated-Layout-Height: 0 @ 1000),

debido a que las prioridades son iguales a 1000. Necesitamos establecer la máxima prioridad bajo la prioridad UIView-Encapsulated-Layout-Height .

Estaba recibiendo un mensaje como este:

Incapaz de satisfacer restricciones simultáneamente …



NSLayoutConstraint: 0x7fe74bdf7e50 ‘UIView-Encapsulated-Layout-Height’ V: [UITableViewCellContentView: 0x7fe75330c5c0 (21.5)]


Intentará recuperarse rompiendo la restricción NSLayoutConstraint: 0x7fe0f9b200c0 UITableViewCellContentView: 0x7fe0f9b1e090.bottomMargin == UILabel: 0x7fe0f9b1e970.bottom

Estoy usando una UITableViewCell personalizada con UITableViewAutomaticDimension para la altura. Y también he implementado el método estimatedHeightForRowAtIndex:

La restricción que me estaba dando problemas se parecía a esto

 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[title]-|" options:0 metrics:nil views:views]; 

Cambiar la restricción a esto solucionará el problema, pero al igual que otra respuesta, sentí que esto no era correcto, ya que disminuye la prioridad de una restricción que deseo que se requiera:

 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6@999-[title]-6@999-|" options:0 metrics:nil views:views]; 

Sin embargo, lo que noté es que si realmente eliminé la prioridad, esto también funciona y no obtengo los registros de restricción de interrupción:

 [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6-[title]-6-|" options:0 metrics:nil views:views]; 

Esto es un poco misterioso sobre cuál es la diferencia entre |-6-[title]-6-| y |-[title-| . Pero especificar el tamaño no es un problema para mí y elimina los registros, y no necesito disminuir la prioridad de mis restricciones requeridas.

Como menciona Jesse en el comentario de la pregunta, esto funciona para mí:

 self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; 

FYI, este problema no ocurre en iOS 10.

Establezca esta view.translatesAutoresizingMaskIntoConstraints = NO; debería resolver este problema