How to split long NSString into pages

人走茶凉 提交于 2019-11-26 20:15:31

问题


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.


回答1:


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.



来源:https://stackoverflow.com/questions/3812692/how-to-split-long-nsstring-into-pages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!