sketch - ios autolayout programmatically
UILabel no ajusta el texto correctamente a veces(diseño automático) (3)
Tengo una configuración uilabel en una vista. No tiene una restricción de ancho, pero su ancho está determinado por una restricción principal a la imagen en miniatura y una restricción final al borde de la vista.
La etiqueta está configurada para tener 0 líneas y para ajustar la palabra. Tengo entendido que esto debería hacer que el marco del uilabel crezca, y de hecho lo hace a veces. (Antes del diseño automático, calcularía y actualizaría el marco de la etiqueta en el código).
El resultado es que funciona correctamente en algunos casos y no en otros. Ver la mayoría de las celdas que funcionan correctamente allí, pero la última celda parece ser demasiado grande. De hecho, es el tamaño correcto. El título "Fair Oaks Smog Check Test" en realidad termina con "Only". Entonces mi cálculo para el tamaño de la celda es correcto, debería ser de ese tamaño. Sin embargo, la etiqueta no ajusta el texto por el motivo que sea. Su ancho de cuadro no se extiende hacia la derecha, así que ese no es el problema.
Entonces, ¿qué está pasando aquí? Es 100% coherente, siempre en esa celda y no en las de arriba, lo que me hace pensar que está relacionado con el tamaño del texto, y UILabel no está volviendo a diseñar el texto una vez que esta vista se agrega a la celda (que lo hace realmente más pequeño ancho sabio).
¿Alguna idea?
Alguna información adicional
La altura de las celdas se calcula a partir de una celda de muestra que creo y almaceno en una variable estática:
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.items.count == 0) {
return 60;
}
static TCAnswerBuilderCell *cell = nil;
static dispatch_once_t pred;
dispatch_once(&pred,
^{
// get a sample cellonce
cell = [tableView dequeueReusableCellWithIdentifier:TC_ANSWER_BUILDER_CELL];
});
[cell configureCellWithThirdPartyObject:self.items[indexPath.row]];
return [cell heightForCellWithTableWidth:self.tableView.frame.size.width];
}
Configuro la célula con mi objeto de datos sobre la marcha, y luego llamo a un método que tengo sobre él que calcula la altura de la celda con un ancho de tabla dado (no siempre se puede confiar en que el cuadro de celda sea correcto al principio).
Esto a su vez llama un método de altura en mi opinión, ya que es realmente donde vive la etiqueta:
- (CGFloat)heightForCellWithTableWidth:(CGFloat)tableWidth {
// subtract 38 from the constraint above
return [self.thirdPartyAnswerView heightForViewWithViewWidth:tableWidth - 38];
}
Este método determina la altura calculando el ancho correcto de la etiqueta y luego haciendo un cálculo:
- (CGFloat)heightForViewWithViewWidth:(CGFloat)viewWidth {
CGFloat widthForCalc = viewWidth - self.imageFrameLeadingSpaceConstraint.constant - self.thumbnailFrameWidthConstraint.constant - self.titleLabelLeadingSpaceConstraint.constant;
CGSize size = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:CGSizeMake(widthForCalc, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
CGFloat returnHeight = self.frame.size.height - self.titleLabel.frame.size.height + size.height;
CGFloat height = returnHeight < self.frame.size.height ? self.frame.size.height : returnHeight;
return height;
}
Esto funciona 100% correctamente.
Las celdas se crean obviamente en cellForRowAtIndexPath y se configuran de inmediato:
if (self.items.count > 0) {
TCAnswerBuilderCell *cell = [tableView dequeueReusableCellWithIdentifier:TC_ANSWER_BUILDER_CELL forIndexPath:indexPath];
[cell configureCellWithThirdPartyObject:self.items[indexPath.row]];
return cell;
}
En la configuración de la celda, mi vista se carga desde un plumín (se vuelve a utilizar en otro lugar, por lo que no está directamente en la celda). La celda lo agrega de la siguiente manera:
- (void) configureCellWithThirdPartyObject:(TCThirdPartyObject *)object {
self.detailDisclosureImageView.hidden = NO;
if (!self.thirdPartyAnswerView) {
self.thirdPartyAnswerView = [TCThirdPartyAPIHelper thirdPartyAnswerViewForThirdPartyAPIServiceType:object.thirdPartyAPIType];
self.thirdPartyAnswerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:self.thirdPartyAnswerView];
[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[_thirdPartyAnswerView]-38-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:NSDictionaryOfVariableBindings(_thirdPartyAnswerView)]];
}
[self.thirdPartyAnswerView configureViewForThirdPartyObject:object forViewStyle:TCThirdPartyAnswerViewStyleSearchCell];
}
Finalmente mi configuración de vista se ve así:
- (void) configureViewForThirdPartyObject:(TCTPOPlace *)object forViewStyle:(TCThirdPartyAnswerViewStyle) style {
self.titleLabel.text = object.name;
self.addressLabel.text = [NSString stringWithFormat:@"%@, %@, %@", object.address, object.city, object.state];
self.ratingsLabel.text = [NSString stringWithFormat:@"%d Ratings", object.reviewCount];
NSString *ratingImageName = [NSString stringWithFormat:@"yelp_star_rating_%.1f.png", object.rating];
UIImage *ratingsImage = [UIImage imageNamed:ratingImageName];
if (ratingsImage) {
self.ratingImageView.image = ratingsImage;
}
if (object.imageUrl) {
[self.thumbnailImageView setImageWithURL:[NSURL URLWithString:object.imageUrl] completed:nil];
}
}
Una especie de solución, pero no entiendo por qué
- Mi subvista se diseñó con un ancho de 320, pero no tiene restricciones propias para el ancho
- La subvista se agregó a la celda, pero con restricciones horizontales que se ven así:
-
@"|[_thirdPartyAnswerView]-38-|"
-
- La vista se configuró inmediatamente después de agregarse a la celda, lo que significa que el texto para el títuloLabel se estableció en ese momento.
- Por alguna razón, el texto fue presentado como si la vista tuviera 320 completos en lugar de 282.
- La etiqueta nunca se actualizó, aunque el marco de la subvista se actualizó a 282, y hubo restricciones en la etiqueta que lo mantendrían dimensionado correctamente.
- Cambiar el tamaño de la vista en el xib 282 solucionó el problema, porque la etiqueta tiene el tamaño correcto para comenzar.
Todavía no entiendo por qué la etiqueta no se vuelve a diseñar después de que el tamaño de la vista principal se actualiza cuando tiene restricciones iniciales y finales.
SOLUCIONADO
Vea la respuesta de Matt a continuación: https://stackoverflow.com/a/15514707/287403
En caso de que no lea el comentario, el problema principal fue que, sin saberlo, establecí preferredMaxLayoutWidth
mediante IB al diseñar una vista con un ancho mayor al que se mostraría (en algunos casos). preferredMaxLayoutWidth
es lo que se usa para determinar dónde se ajusta el texto. Por lo tanto, aunque mi vista y titleLabel se redimensionaron correctamente, el preferredMaxLayoutWidth
todavía estaba en el valor anterior y causaba que se envolviera en puntos inesperados. En su lugar, establecer el título Label en su tamaño automático (⌘ = en IB) y actualizar el preferredMaxLayoutWidth
forma dinámica en layoutSubviews
antes de llamar a super fue la clave. Gracias Matt!
Además, compruebe que está pasando números enteros a sus restricciones de diseño en el código.
Para mí sucedió que después de algunos cálculos (por ejemplo, convertPoint: toView :), estaba pasando algo así como 23.99999997, y eventualmente esto llevó a una etiqueta de 2 líneas que se mostraba como una línea (aunque su marco parecía calcularse correctamente) . En mi caso, ¡CGRectIntegral hizo el truco!
Los errores de redondeo podrían matarte :)
Soy una persona que ha escrito una aplicación que usa la función de ajuste automático de cinco etiquetas en una celda de una tabla cuyas celdas tienen diferentes alturas, donde las etiquetas se redimensionan a sí mismas de acuerdo con lo que contienen y funciona. Voy a sugerir, por lo tanto, que la razón por la que está teniendo problemas podría ser que sus restricciones no determinan demasiado el diseño, es decir, que tiene un diseño ambiguo para los elementos de la celda. No puedo probar esa hipótesis porque no puedo ver tus limitaciones. Pero puede verificar fácilmente (creo) utilizando po [[UIWindow keyWindow] _autolayoutTrace]
cuando se pausa en el depurador.
También tengo otra sugerencia (lo siento por tirar cosas): asegúrese de que está configurando el MaxLayoutWidth preferredMaxLayoutWidth
la etiqueta. Esto es crucial porque es el ancho con el que la etiqueta dejará de crecer horizontalmente y comenzará a crecer verticalmente.
Tuve el mismo problema y lo resolví usando una sugerencia de esta respuesta . En una subclase de UILabel coloqué este código:
- (void)layoutSubviews
{
[super layoutSubviews];
self.preferredMaxLayoutWidth = self.bounds.size.width;
}
No entiendo por qué este no es el comportamiento predeterminado de UILabel, o al menos por qué no puedes simplemente habilitar este comportamiento a través de un indicador.
Estoy un poco preocupado de que preferredMaxLayoutWidth se establezca en el medio del proceso de diseño, pero no veo una manera fácil de evitarlo.