2010-07-30 105 views
9

在下面的代碼中,CTFramesetterSuggestFrameSizeWithConstraints有時會返回一個CGSize,其高度不足以包含傳入其中的所有文本。我確實看過this answer。但在我的情況下,文本框的寬度需要保持不變。有沒有其他的/更好的方法來找出我的屬性字符串的正確高度?謝謝!CTFramesetterSuggestFrameSizeWithConstraints有時會返回不正確的大小?

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

對此有何進展? – hfossli 2010-08-10 11:10:06

回答

19

CTFramesetterSuggestFrameSizeWithConstraints()壞了。我早就提出了一個錯誤。您的替代方案是使用CTFramesetterCreateFrame(),其路徑足夠高。然後你可以測量你回來的CTFrame的矩形。請注意,您無法使用CGFLOAT_MAX作爲高度,因爲CoreText使用iPhone中的翻轉座標系並將其文本定位在框的「頂部」。這意味着如果你使用CGFLOAT_MAX,你將不會有足夠的精確度來實際判斷盒子的高度。我建議使用類似10,000的高度作爲高度,因爲它比屏幕本身高10倍,並且爲所得到的矩形提供了足夠的精度。如果你需要設計更高的文本,你可以對文本的每一部分進行多次這樣的操作(你可以向CTFrameRef提供它能夠佈局的原始字符串的範圍)。

+1

CGFLOAT_MAX在當前情況下確實是一個問題,將該值設置爲100.000似乎工作得很好。仍然很奇怪,我只在iOS5上面對這個問題。 – GregoryM 2011-11-14 15:57:32

+1

@GregoryM:是的,這就是爲什麼我建議使用類似10,000的東西,這是我使用的值(足夠大有用,足夠小,仍然允許小數部分有足夠的精度)。 – 2011-11-14 18:24:58

+0

這是一箇舊的答案,但你如何從CGFrame獲取CGRect或高度? – 2013-12-05 02:27:10

51

CTFramesetterSuggestFrameSizeWithConstraints正常工作。之所以會得到太短的高度,是因爲在默認的段落樣式中引用了屬性字符串。如果您沒有爲字符串添加段落樣式,則CoreText將返回呈現文本所需的高度,但行之間沒有空格。這讓我永遠不知所措。文檔中沒有任何內容可以說明。我恰巧注意到我的身高縮短了一個等於(行數x預計領先)的數量。爲了讓你期望你可以使用如下代碼高度結果如下:

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

如何在屬性字符串中包含多個字體時完成此操作? – bogardon 2012-07-20 14:52:22

+0

您可以使用CFAttributedStringSetAttributes將段落屬性添加到字符串並將clearOtherAttributes傳遞給NO。 – gaige 2012-09-06 15:16:50

+0

我一直在尋找這一個非常感謝你Chris! – stefanosn 2012-10-17 23:10:23

-6

我終於找到。當使用CTFramesetterSuggestFrameSizeWithConstraints返回CGSize繪製文本,大小被認爲是整個不夠(有時)大文本,所以最後一行不是提請..我只是加1 size.height返回,它似乎是現在。

像這樣:

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

+0

完全不起作用:/ – kubbing 2013-04-08 17:26:22

0

感謝Chris DeSalvo的出色答案!最後結束16小時的調試。我在計算Swift 3語法時遇到了一些問題。所以分享了設置段落樣式的Swift 3版本。

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