我无法强制 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
上面是一个粗略的摘录 - 我在初始化程序中计算了 CTLine 的边界,然后在获取单词的框架时只计算左 + 右端点。
哇!