iphone - 如何计算帧大小以按行绘制 CoreText

标签 iphone ios objective-c ipad core-text

我正在尝试根据拆分成多个部分的长 NSAttributedString 动态创建书页。

我现在正在做的是将这个类别用于NSAttributedString:

@interface NSAttributedString (Height)
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth;
@end

@implementation NSAttributedString (Height)

- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth
{
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)self); 
    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, 10000), NULL);
    CFRelease(framesetter);
    return suggestedSize.height ;
}
@end

因为我是使用 CTFramesetter 绘制文本,所以它工作正常并且正确返回了框的正确高度。 不幸的是现在我需要逐行绘制文本:

-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();

// Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
//CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

NSArray *lines = (__bridge NSArray *)(CTFrameGetLines(ctFrame));

CFIndex lineCount = [lines count];

for(CFIndex idx = 0; idx < lineCount; idx++)
{
    // For each line found from where it starts and it's length
    CTLineRef line = CFArrayGetValueAtIndex((CFArrayRef)lines, idx);
    CFRange lineStringRange = CTLineGetStringRange(line);
    NSRange lineRange = NSMakeRange(lineStringRange.location, lineStringRange.length);
    // Get the line related string 
    NSString* lineString = [displayedString.string substringWithRange:lineRange];
    // Calculate it's range
    NSRange stringRange = NSMakeRange(lineStringRange.location, lineStringRange.length);

    static const unichar softHypen = 0x00AD;
    // Get the last char of the line
    unichar lastChar = [lineString characterAtIndex:stringRange.length-1];
    // Check if it's a soft hyphenation character
    if(softHypen == lastChar) {
        NSMutableAttributedString* lineAttrString = [[displayedString attributedSubstringFromRange:stringRange] mutableCopy];
        NSRange replaceRange = NSMakeRange(stringRange.length-1, 1);
        // Replace it with an hard hyphenation character
        [lineAttrString replaceCharactersInRange:replaceRange withString:@"-"];

        CTLineRef hyphenLine = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)lineAttrString);
        CTLineRef justifiedLine = CTLineCreateJustifiedLine(hyphenLine, 1.0, self.frame.size.width);

        CGFloat ascent;
        CGFloat descent;
        // Calculate the line height
        CTLineGetTypographicBounds(justifiedLine, &ascent, &descent, NULL);
        // Set the correct position for the line
        CGContextSetTextPosition(context, 0.0, idx*-(ascent + descent)-ascent);
        CTLineDraw(justifiedLine, context);
    }
    else{
        CGFloat ascent;
        CGFloat descent;
        // Calculate the line height
        CTLineGetTypographicBounds(line, &ascent, &descent, nil);
        CGFloat y = idx*-(ascent + descent)-ascent;
        // Set the correct position for the line
        CGContextSetTextPosition(context, 0.0, y);

        CTLineDraw(line, context);
    }
}

这几乎可以正常工作,但并非总是如此。有时会发生这种情况:

Last string cutted out

如您所见,最后一行被剪掉了。 有人有什么建议来解决这个烦人的问题吗?

最佳答案

由于某些原因,(ascent + descent) 似乎不是直线的正确高度。实际上 ascender + 1 + descender 等于 Point Size。

简单地改变这个:

CGContextSetTextPosition(context, 0.0, idx*-(ascent + descent)-ascent);

进入这个:

CGContextSetTextPosition(context, 0.0, idx*-(ascent - 1 + descent)-ascent);

成功了。 引用:Cocoanetics article about UIFont . 感谢 jverrijt 的提示!

关于iphone - 如何计算帧大小以按行绘制 CoreText,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15310236/

相关文章:

iphone - EXC_BAD_ACCESS 当 popViewController

ios - 如何刷新每个 View 的多语言控件

ios - 请帮助我理解这些代码行

ios - Safari 不会通过 http/2 加载一些资源

ios - 检测用户何时离开 viewController

iphone - 如何向服务器写入数据?

iphone - UIPageViewController 手势问题

ios - 从服务器发送和获取设备位置

ios - 当从相机 ios 选择图像时,在 tableview 中加载不同的图像

ios - 如何在可调整大小的 UITableviewCell 中添加 UITextView