ios - concatenate - NSString boundingRectWithSize devolviendo altura innecesariamente alta
concatenate string objective c (4)
Al usar [NSString boundingRectWithSize:options:attributes]
el tamaño del rect que se devuelve es más alto de lo que esperaría para ciertas cadenas. La altura devuelta parece representar la altura máxima posible de una cadena con los atributos dados, en lugar de la altura de la cadena en sí.
Asumiendo los mismos atributos y opciones, la altura devuelta para la cadena " cars
" es la misma altura devuelta para la cadena " ÉTAS-UNIS
" (note el acento en la E).
Hubiera esperado que boundingRectWithSize
solo considerara los caracteres de la cadena dada, lo que en mi opinión le devolvería una altura más corta para la cadena " cars
".
En las capturas de pantalla adjuntas, he llenado el rect devuelto de boundingRectWithSize
y he resaltado en rojo lo que habría asumido que el rect delimitador debería haber sido. El ancho del rect es bastante parecido al que esperaría, pero la altura es considerablemente más alta de lo que hubiera esperado. ¿Porqué es eso?
Código de muestra:
NSRect boundingRect = NSZeroRect;
NSSize constraintSize = NSMakeSize(CGFLOAT_MAX, 0);
NSString *lowercaseString = @"cars";
NSString *uppercaseString = @"ÉTAS-UNIS";
NSString *capitalizedString = @"Japan";
NSFont *drawingFont = [NSFont fontWithName:@"Georgia" size:24.0];
NSDictionary *attributes = @{NSFontAttributeName : drawingFont, NSForegroundColorAttributeName : [NSColor blackColor]};
boundingRect = [lowercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Lowercase rect: %@", NSStringFromRect(boundingRect));
boundingRect = [uppercaseString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Uppercase rect: %@", NSStringFromRect(boundingRect));
boundingRect = [capitalizedString boundingRectWithSize:constraintSize options:0 attributes:attributes];
NSLog(@"Capitalized rect: %@", NSStringFromRect(boundingRect));
Salida:
Lowercase rect: {{0, -6}, {43.1953125, 33}}
Uppercase rect: {{0, -6}, {128.44921875, 33}}
Capitalized rect: {{0, -6}, {64.5, 33}}
@omz todavía recibe crédito por hacer que esto funcione para mí. Su respuesta me hizo mirar un poco más alrededor del CoreText, ya que asumí que algo como boundingRectWithSize
finalmente llama una función CoreText.
En la sesión 226 de WWDC 2012 había una sección completa dedicada a calcular las métricas de una línea y, para mi sorpresa, hablaron sobre una nueva función CTLineGetBoundsWithOptions
llamada CTLineGetBoundsWithOptions
.
Por lo que puedo decir, ese método solo está documentado en CTLine.h
y en el documento de CoreText Changes
. Ciertamente no aparece (para mí) cuando se realiza una búsqueda normal en la documentación.
Pero parece que funciona y en mis pruebas devuelve exactamente el mismo resultado que boundingRectWithSize
para todas las fuentes instaladas en mi sistema. Aún mejor, es que parece ser casi 2 veces más rápido que boundingRectWithSize
.
Como lo menciona el video de la WWDC, es un poco oscuro por qué tendría que calcular los límites de una cadena sin tener en cuenta cosas como la altura de la línea, pero si necesita hacerlo, entonces creo que este podría ser el mejor método para utilizar. Como siempre, YMMV.
Código de muestra en bruto:
NSFont *font = [NSFont systemFontOfSize:13.0];
NSDictionary *attributes = @{(__bridge NSString *)kCTFontAttributeName : font};
NSAttributedString *attributeString = [[NSAttributedString alloc] initWithString:self.text attributes:attributes];
CTLineRef line = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attributeString);
CGRect bounds = CTLineGetBoundsWithOptions(line, kCTLineBoundsUseGlyphPathBounds);
CFRelease(line);
return NSRectFromCGRect(bounds);
Es posible que desee utilizar NSStringDrawingUsesDeviceMetrics
en las opciones. De los docs :
NSStringDrawingUsesDeviceMetrics
Utilice los límites de los glifos de la imagen (en lugar de los límites tipográficos) al calcular el diseño.
Solución Swift 3+ basada en la respuesta de omz :
let string: NSString = "test"
let maxSize = NSSize(width: CGFloat.greatestFiniteMagnitude, height: .greatestFiniteMagnitude)
let boundingRect = string.boundingRect(with: maxSize, options: .usesDeviceMetrics, attributes: <string attributes>)
boundingRectWithSize
función boundingRectWithSize
, pero no funcionó para mí.
Lo que funcionó fue sizeThatFits
Uso:
CGSize maxSize = CGSizeMake(myLabel.frame.size.width, CGFLOAT_MAX)
CGSize size = [myLabel sizeThatFits:maxSize];