2010-07-30 18 views
9

En el código siguiente, CTFramesetterSuggestFrameSizeWithConstraints a veces devuelve CGSize con una altura que no es lo suficientemente grande como para contener todo el texto que se está pasando en ella. Miré this answer. Pero en mi caso, el ancho del cuadro de texto debe ser constante. ¿Hay alguna otra/mejor forma de calcular la altura correcta para mi cadena atribuida? ¡Gracias!CTFramesetterSuggestFrameSizeWithConstraints a veces devuelve un tamaño incorrecto?

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attributedString); 
CGSize tmpSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, CGSizeMake(self.view.bounds.size.width, CGFLOAT_MAX), NULL); 
CGSize textBoxSize = CGSizeMake((int)tmpSize.width + 1, (int)tmpSize.height + 1); 
+0

¿algún progreso en esto? – hfossli

Respuesta

19

CTFramesetterSuggestFrameSizeWithConstraints() está roto. Archivé un error en esto hace un tiempo. Su alternativa es usar CTFramesetterCreateFrame() con una ruta lo suficientemente alta. Entonces puedes medir el rect del CTFrame que recuperas. Tenga en cuenta que no puede usar CGFLOAT_MAX para la altura, ya que CoreText usa un sistema de coordenadas volteado desde el iPhone y ubicará su texto en la "parte superior" de la casilla. Esto significa que si usa CGFLOAT_MAX, no tendrá la precisión suficiente para decir la altura de la caja. Recomiendo utilizar algo así como 10,000 como su altura, ya que es 10 veces más alto que la pantalla en sí y, sin embargo, da la precisión suficiente para el rectángulo resultante. Si necesita diseñar texto aún más alto, puede hacerlo varias veces para cada sección de texto (puede pedirle a CTFrameRef el rango en la cadena original que pudo diseñar).

+1

CGFLOAT_MAX es realmente un problema en el caso actual, establecer el valor a 100.000 parece funcionar muy bien. Aún así, es extraño que enfrente este problema solo en iOS5. – GregoryM

+1

@GregoryM: Sí, es por eso que sugerí usar algo así como 10,000, que es el valor que utilicé (lo suficientemente grande para ser útil, lo suficientemente pequeño como para permitir todavía mucha precisión en la parte fraccionaria). –

+0

esta es una respuesta antigua, pero ¿cómo se obtiene el CGRect o la altura de un CTFrame? –

51

CTFramesetterSuggestFrameSizeWithConstraints funciona correctamente. La razón por la que obtiene una altura que es demasiado corta es debido a la ventaja en el estilo de párrafo predeterminado asociado a las cadenas atribuidas. Si no adjunta un estilo de párrafo a la cadena, CoreText devuelve la altura necesaria para representar el texto, pero sin espacio entre las líneas. Esto me tomó una eternidad para descubrirlo. Nada en la documentación lo deletrea. Solo me di cuenta de que mis alturas eran cortas en una cantidad igual a (número de líneas x líder esperado). Para obtener el resultado que esperas altura puede utilizar código como el siguiente:

NSString *text = @"This\nis\nsome\nmulti-line\nsample\ntext." 
UIFont *uiFont = [UIFont fontWithName:@"Helvetica" size:17.0]; 
CTFontRef ctFont = CTFontCreateWithName((CFStringRef) uiFont.fontName, uiFont.pointSize, NULL); 

// When you create an attributed string the default paragraph style has a leading 
// of 0.0. Create a paragraph style that will set the line adjustment equal to 
// the leading value of the font. 
CGFloat leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender; 
CTParagraphStyleSetting paragraphSettings[1] = { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &leading }; 

CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1); 
CFRange textRange = CFRangeMake(0, text.length); 

// Create an empty mutable string big enough to hold our test 
CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, text.length); 

// Inject our text into it 
CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) text); 

// Apply our font and line spacing attributes over the span 
CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont); 
CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle); 

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(string); 
CFRange fitRange; 

CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, bounds, &fitRange); 

CFRelease(framesetter); 
CFRelease(string); 
+1

Entonces, ¿cómo se hace esto cuando tiene varias fuentes en la cadena atribuida? – bogardon

+0

Puede agregar el atributo de párrafo a la cadena mediante el uso de '' CFAttributedStringSetAttributes'' y pasar NO por 'clearOtherAttributes' – gaige

+0

Estaba buscando esta, ¡muchas gracias, Chris! – stefanosn

-6

finalmente me entero .. Cuando utiliza CTFramesetterSuggestFrameSizeWithConstraints regresan CGSize para dibujar texto, el tamaño es considerado no es suficiente (a veces) grande para el conjunto texto, por lo que la última línea no se dibuja ... Simplemente agrego 1 a size.height para devolver, parece ser ahora.

algo como esto:

suggestedSize = CGSizeMake (suggestedSize.width, suggestedSize.height + 1);

+0

totalmente no funciona: / – kubbing

0

¡Gracias a Chris DeSalvo por la excelente respuesta! Finalmente termina 16 horas de depuración. Me costó un poco descifrar la sintaxis de Swift 3. Así que compartir la versión de Swift 3 de establecer el estilo de párrafo.

let leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender 
let paragraphStyle = NSMutableParagraphStyle() 
paragraphStyle.lineSpacing = leading  
mutableAttributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: textRange) 
Cuestiones relacionadas