2010-07-30 17 views
9

Dans le code ci-dessous, CTFramesetterSuggestFrameSizeWithConstraints renvoie parfois un CGSize avec une hauteur qui n'est pas assez grande pour contenir tout le texte qui y est passé. J'ai regardé this answer. Mais dans mon cas, la largeur de la zone de texte doit être constante. Existe-t-il une autre/meilleure façon de déterminer la hauteur correcte pour ma chaîne attribuée? Merci!CTFramesetterSuggestFrameSizeWithConstraints renvoie parfois une taille incorrecte?

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

des progrès à ce sujet? – hfossli

Répondre

19

CTFramesetterSuggestFrameSizeWithConstraints() est cassé. J'ai déposé un bug sur cela il y a un certain temps. Votre alternative est d'utiliser CTFramesetterCreateFrame() avec un chemin suffisamment élevé. Ensuite, vous pouvez mesurer le rect du CTFrame que vous récupérez. Notez que vous ne pouvez pas utiliser CGFLOAT_MAX pour la hauteur, car CoreText utilise un système de coordonnées inversé de l'iPhone et trouvera son texte en haut de la boîte. Cela signifie que si vous utilisez CGFLOAT_MAX, vous n'aurez pas assez de précision pour déterminer la hauteur de la boîte. Je recommande d'utiliser quelque chose comme 10 000 comme votre taille, car il est 10 fois plus grand que l'écran lui-même et donne suffisamment de précision pour le rectangle résultant. Si vous avez besoin de mettre en page un texte encore plus grand, vous pouvez le faire plusieurs fois pour chaque section de texte (vous pouvez demander à CTFrameRef la gamme dans la chaîne d'origine qu'il a pu mettre en page).

+1

CGFLOAT_MAX est vraiment un problème dans le cas actuel, mettre la valeur à 100.000 semble fonctionner très bien. Pourtant, il est étrange que je fais face à ce problème uniquement sur iOS5. – GregoryM

+1

@GregoryM: Oui, c'est pourquoi j'ai suggéré d'utiliser quelque chose comme 10 000, qui est la valeur que j'ai utilisée (assez grande pour être utile, assez petite pour permettre encore beaucoup de précision dans la partie fractionnaire). –

+0

c'est une vieille réponse mais comment obtenez-vous le CGRect ou la hauteur d'un CTFrame? –

51

CTFramesetterSuggestFrameSizeWithConstraints fonctionne correctement. La raison pour laquelle vous obtenez une hauteur trop courte est due à l'interlignage dans le style de paragraphe par défaut attaché aux chaînes attribuées. Si vous n'attachez pas de style de paragraphe à la chaîne, CoreText renvoie la hauteur nécessaire pour afficher le texte, mais sans espace entre les lignes. Cela m'a pris pour toujours à comprendre. Rien dans la documentation ne l'énonce. Je viens juste de remarquer que mes hauteurs étaient courtes d'un montant égal à (nombre de lignes x attendues menant). Pour obtenir le résultat de la hauteur que vous attendez, vous pouvez utiliser le code comme suit:

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

alors comment cela se fait-il lorsque vous avez plusieurs polices dans la chaîne attribuée? – bogardon

+0

Vous pouvez ajouter l'attribut de paragraphe à la chaîne en utilisant '' CFAttributedStringSetAttributes'' et passer NO pour 'clearOtherAttributes' – gaige

+0

Je cherchais celui-ci merci beaucoup Chris! – stefanosn

-6

je enfin découvre .. Quand utilise CTFramesetterSuggestFrameSizeWithConstraints retour CGSize pour dessiner le texte, la taille est considérée comme pas assez grand (parfois) pour l'ensemble texte, donc la dernière ligne n'est pas dessinée .. Je viens d'ajouter 1 à size.height pour le retour, il semble être en ce moment.

comme ceci:

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

+0

ne fonctionne pas totalement: / – kubbing

0

Merci à Chris DeSalvo pour l'excellente réponse! Enfin se terminant 16 heures de débogage. J'ai eu un peu de mal à comprendre la syntaxe de Swift 3. Donc, partager la version Swift 3 de la définition du style de paragraphe.

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