我在iOS上将一个多行字符串分解成单词边界。我的解决方案以NSLayoutManager的boundingRectForGlyphRange方法为中心。它几乎可以工作,除了每个单词的矩形在右边几个像素之外。换句话说,NSLayoutManager似乎在每一行都添加了前导空格/缩进,我找不到任何方法来覆盖这种行为。
我尝试使用NSLayoutManager.usesFontLeading和NSParagraphStyle.headIndent,但没有任何结果:
NSLayoutManager* layout = [NSLayoutManager new];
layout.usesFontLeading = NO;
NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.headIndent = paragraphStyle.firstLineHeadIndent = 0;
NSTextStorage* textStorage = [[NSTextStorage alloc] initWithString:self attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}];
layout.textStorage = textStorage;
NSTextContainer* textContainer = [[NSTextContainer alloc] initWithSize:size];
[layout addTextContainer:textContainer];
// compute bounding rect for each word range
for (NSValue* wordRangeValue in wordRanges)
{
NSRange wordRange = [wordRangeValue rangeValue];
NSRange wordGlyphRange = [layout glyphRangeForCharacterRange:wordRange actualCharacterRange:NULL];
CGRect wordBounds = [layout boundingRectForGlyphRange:wordGlyphRange inTextContainer:textContainer];
}

屏幕截图:灰色矩形表示标签边界,红色矩形表示每个标签的文本矩形,并通过上面的boundingRectForGlyphRange:方法计算单词边界。请注意,计算的单词边界偏离了几个像素。
我也对计算单词边界的其他方法持开放态度,但boundingRectForGlyphRange似乎对我的目的非常方便。
发布于 2014-05-22 23:00:11
要忽略左边距,请使用:
textContainer.lineFragmentPadding = 0;发布于 2014-02-10 09:13:04
我不能强迫NSLayoutManager省略左边距。如果有人知道如何让NSLayoutManager忽略左边距,请告诉我。
我的变通方法是使用Core Text。这要困难得多,也复杂得多。我的解决方案不适合粘贴到单个代码摘录中,但如果你想走同样的路,这应该会给你一个很好的参考:
- (NSArray*) coreTextLayoutsForCharacterRanges:(NSArray*)ranges withFont:(UIFont *)font constrainedToSize:(CGSize)size{
// initialization: make frame setter
NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; // watch out - need to specify line wrapping to use multi line layout!
paragraphStyle.minimumLineHeight = font.lineHeight; // watch out - custom fonts do not compute properly without this!
NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:self attributes:@{NSFontAttributeName:font, NSParagraphStyleAttributeName:paragraphStyle}];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);
CFRange wholeString = CFRangeMake(0, self.length);
CGRect bounds = CGRectMake(0, 0, size.width, size.height);
CGMutablePathRef boundsPath = CGPathCreateMutable();
CGPathAddRect(boundsPath, NULL, bounds);
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, wholeString, boundsPath, NULL);
CFRelease(boundsPath);
// extract lines
CFArrayRef lines = CTFrameGetLines(frame);
int lineCount = CFArrayGetCount(lines);
CGPoint lineOrigins[lineCount];
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), lineOrigins);
NSMutableArray* lineLayouts = [NSMutableArray arrayWithCapacity:lineCount];
CGFloat h = size.height;
for (int i = 0; i < lineCount; ++i){
CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
CGPoint lineOrigin = lineOrigins[i]; // in Core Graphics coordinates! let's convert.
lineOrigin.y = h - lineOrigin.y;
TextLayout* lineLayout = [[CTLineLayout alloc] initWithString:self line:line lineOrigin:lineOrigin];
[lineLayouts addObject:lineLayout];
}
// got line layouts. now we iterate through the word ranges to find the appropriate line for each word and compute its layout using the corresponding CTLine.另一个重要的部分是如何使用CTLine获取一行中单词的边界矩形。我将其分解到一个CTLineLayout模块中,但要点是这样的( ' origin‘变量指的是在上面的代码示例中计算的线原点):
CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f;
CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
CGFloat top = origin.y - ascent;
CGFloat bottom = origin.y + descent;
CGRect result = CGRectMake(origin.x, top, width, bottom - top); // frame of entire line (for now)
CGFloat left = CTLineGetOffsetForStringIndex(line, stringRange.location, NULL);
CGFloat right = CTLineGetOffsetForStringIndex(line, NSMaxRange(stringRange), NULL);
result.origin.x = left;
result.size.width = right - left; // frame of target word in UIKit coordinates上面是一个粗略的摘录-I分解CTLine,在初始化器中计算一次行的边界,然后在获得一个单词的帧时只计算左+右端点。
呼!
https://stackoverflow.com/questions/21666258
复制相似问题