如何将长 NSString 拆分为页面
我有一个很长的 NSString 我想在几页上显示。
但要做到这一点,我需要找出页面上实际适合的文本量。
[NSString sizeWithFont: ...] 还不够,它只会告诉我文本是否适合矩形,如果不适合,它会默默地截断字符串,但不会告诉我截断的位置!
我需要知道第一个不适合页面的单词,这样我就可以分割字符串并将其部分绘制在下一页上。 (并重复)
有什么想法可以解决这个问题吗?
到目前为止,我自己唯一的想法是在字符串中我猜测分页符所在的点周围重复调用 sizeWithFont:constrainedToSize: ,并分析生成的矩形,但感觉很麻烦且缓慢,我觉得我可能有要使其 100% 准确,还存在其他问题...(因为下降部分等等。)
ofc,它必须在公共 iOS SDK 中可用
答案:
唷,那是一些毛茸茸的文档。这是我完成的函数作为示例,也许它会对某人有所帮助,因为那里没有太多特定于 iphone 的核心文本示例。
+ (NSArray*) findPageSplits:(NSString*)string size:(CGSize)size font:(UIFont*)font;
{
NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:32];
CTFontRef fnt = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize,NULL);
CFAttributedStringRef str = CFAttributedStringCreate(kCFAllocatorDefault,
(CFStringRef)string,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:(id)fnt,kCTFontAttributeName,nil]);
CTFramesetterRef fs = CTFramesetterCreateWithAttributedString(str);
CFRange r = {0,0};
CFRange res = {0,0};
NSInteger str_len = [string length];
do {
CTFramesetterSuggestFrameSizeWithConstraints(fs,r, NULL, size, &res);
r.location += res.length;
[result addObject:[NSNumber numberWithInt:res.length]];
} while(r.location < str_len);
// NSLog(@"%@",result);
CFRelease(fs);
CFRelease(str);
CFRelease(fnt);
return result;
}
重要提示:
您不能将返回的范围或大小与任何 UIKit 类或字符串绘制函数一起使用!您只能将其与 Core Text 一起使用,例如创建 CTFrame 并绘制它。 诸如字距调整之类的细微差别使得 Core Text 功能与 UIKit 结合起来变得不可能。
另请注意,已发现返回的大小有问题。
I have a long NSString I want to display over a couple of pages.
But to do this, I need to find out how much text will actually fit on the page.
[NSString sizeWithFont: ...] Is not enough, it will just tell me if the text fits in the rectangle or not, if its does not, it will silently truncate the string, but it won't tell me where it truncated!
I need to know the first word that does not fit on the page, so I can split the string and draw that part of it on the next page. (and repeat)
Any ideas how to solve this?
Only idea I have myself so far is to repeatedly call sizeWithFont:constrainedToSize: around the point in the string where I'm guessing the page break will be, and analyse the resulting rect, but it feels cumbersome and slow and I feel I might have additional problems getting it 100% accurate... (because of descenders, and whatnot.)
ofc, it has to be available in the public iOS SDK
Answer:
Phew, that was some hairy documentation. Here is my finished function as an example, maybe it will help someone, since there isn't much iphone-specific core text examples out there.
+ (NSArray*) findPageSplits:(NSString*)string size:(CGSize)size font:(UIFont*)font;
{
NSMutableArray* result = [[NSMutableArray alloc] initWithCapacity:32];
CTFontRef fnt = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize,NULL);
CFAttributedStringRef str = CFAttributedStringCreate(kCFAllocatorDefault,
(CFStringRef)string,
(CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:(id)fnt,kCTFontAttributeName,nil]);
CTFramesetterRef fs = CTFramesetterCreateWithAttributedString(str);
CFRange r = {0,0};
CFRange res = {0,0};
NSInteger str_len = [string length];
do {
CTFramesetterSuggestFrameSizeWithConstraints(fs,r, NULL, size, &res);
r.location += res.length;
[result addObject:[NSNumber numberWithInt:res.length]];
} while(r.location < str_len);
// NSLog(@"%@",result);
CFRelease(fs);
CFRelease(str);
CFRelease(fnt);
return result;
}
IMPORTANT NOTE:
You can not use the returned range or size with any UIKit classes or string drawing functions! You must only use it with Core Text, for example creating a CTFrame and drawing that.
Subtle differences in things like kerning makes it impossible to combine Core Text functions with UIKit.
Also, note that the returned size has been found to be buggy.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您应该研究一下 CoreText,它自 iOS 3.2 起可用。这些文档相当复杂,可以在 此处找到。基本上,您创建一个 CTFramesetter 并调用 CTFramesetterSuggestFrameSizeWithConstraints。然后,您将找到适合给定 CGSize 的文本范围。
You should look into CoreText, available since iOS 3.2. The docs are rather complicated and can be found here. Basically you create a CTFramesetter and call CTFramesetterSuggestFrameSizeWithConstraints. You will then find the range of text that fits within a given CGSize.