从一个更长的NSString中返回一个单词包装的NSString

可能重复:
UITextView:获取带有换行信息的文本

我一直在探索NSString库和众多的函数库,可以采取这样一个长string的库:

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. 

并与一个CGSize或浮动宽度,以及正在使用的字体一起,并返回给我一个string\ n中断和单词包装。

结果(大致):

 Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac\n egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet.\n Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. \n placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra.\n Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi.\n Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci,\n sagittis tempus lacus enim ac dui. 

我已经知道,UITextViews等这样做,但这是没有什么帮助,因为我需要在原始的OpenGL格局渲染文本,所以我没有使用常规的UI元素。

我知道这或者作为一个框架存在,或者是某个公共类。 我只是根本找不到任何统一的处理方式。

我想它接近[NSString sizeWithFont:forWidth:lineBreakMode:],但我不需要的大小,我需要的string本身。

实际上没有必要重新发明这个轮子,因为每当你包装文本时,正是文本引擎为你做的。 什么文本引擎? 这是核心文本。 如果你下降到核心文本的水平,并有一个CTFramesetter为你布置文本,你可以通过要求产生的CTLines,了解它在哪里放行。

该文档将帮助您开始:

http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/CoreText_Programming/Operations/Operations.html

网上有很多很好的教程。

简单的例子:

 NSString* s = @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " @"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " @"enim ad minim veniam, quis nostrud exercitation ullamco laboris " @"nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor " @"in reprehenderit in voluptate velit esse cillum dolore eu fugiat " @"nulla pariatur. Excepteur sint occaecat cupidatat non proident, " @"sunt in culpa qui officia deserunt mollit."; NSAttributedString* text = [[NSAttributedString alloc] initWithString:s]; CTFramesetterRef fs = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)text); CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, CGRectMake(0,0,200,100000)); CTFrameRef f = CTFramesetterCreateFrame(fs, CFRangeMake(0, 0), path, NULL); CTFrameDraw(f, NULL); NSArray* lines = (__bridge NSArray*)CTFrameGetLines(f); for (id aLine in lines) { CTLineRef theLine = (__bridge CTLineRef)aLine; CFRange range = CTLineGetStringRange(theLine); NSLog(@"%ld %ld", range.location, range.length); } CGPathRelease(path); CFRelease(f); CFRelease(fs); 

您将会看到,输出显示了每行包装文本的范围。 这不是你以后的事情吗?

似乎没有工厂方式这样做,所以已经开始构build一个类函数来处理这个,基于在这个密切相关的堆栈引入的解决scheme:

 + (NSString*)wrappedString:(NSString*)string withFont:(UIFont*)font andWidth:(float)width { NSMutableString *resultString = [[NSMutableString alloc] initWithString:@""]; CGSize textSize = [string sizeWithFont:font]; float textWidth = textSize.width; if (textWidth < width) { return string; } float wordLength; float lineLength; NSUInteger length = [string length]; unichar buffer[length]; [string getCharacters:buffer range:NSMakeRange(0, length)]; NSString *singleLine = @""; NSString *word = @""; NSString *longWord = @""; for (NSUInteger i = 0; i < length; i++) { unichar character = buffer[i]; if (character != '\n') { word = [NSString stringWithFormat:@"%@%c", word, character]; } if (character == '\n') { float wordLength = [word sizeWithFont:font].width; float lineLength = [singleLine sizeWithFont:font].width; if ((lineLength + wordLength) > width) { [resultString appendString:singleLine]; [resultString appendString:@"\n"]; singleLine = @""; singleLine = [singleLine stringByAppendingFormat:@"%@\n",word]; word = @""; } else { singleLine = [singleLine stringByAppendingString: word]; word = @""; [resultString appendString:singleLine]; [resultString appendString:@"\n"]; singleLine = @""; } } else if (character == ' ') { float wordLength = [word sizeWithFont:font].width; float lineLength = [singleLine sizeWithFont:font].width; if ((lineLength + wordLength) > width) { if (wordLength > textWidth) { [resultString appendString:singleLine]; [resultString appendString:@"\n"]; singleLine = @""; int j = 0; for (; j < [word length]; j++) { unichar longChar = [word characterAtIndex:j]; longWord = [NSString stringWithFormat:@"%@%c", longWord, longChar]; float longwordLength = [longWord sizeWithFont:font].width; float longlineLength = [singleLine sizeWithFont:font].width; if ((longlineLength + longwordLength) >= width) { singleLine = [singleLine stringByAppendingString:longWord]; word = @""; longWord = @""; break; } } } [resultString appendString:singleLine]; [resultString appendString:@"\n"]; singleLine = @""; } singleLine = [singleLine stringByAppendingString: word]; word = @""; } } wordLength = [word sizeWithFont:font].width; lineLength = [singleLine sizeWithFont:font].width; if (wordLength > 0) { if ((lineLength + wordLength) > width) { [resultString appendString:singleLine]; [resultString appendString:@"\n"]; singleLine = @""; } singleLine = [singleLine stringByAppendingString:word]; } if (lineLength > 0) { [resultString appendString:singleLine]; [resultString appendString:@"\n"]; } return resultString; }