iOS CoreText:CTFrameSetter比CGPath允许更宽的行

时间:2012-03-06 01:21:55

标签: objective-c ios core-text

我正在使用CoreText在CGPath中呈现我的文本,这通常是一个矩形。路径的宽度为230像素。但是当我渲染文本时,CTLineGetTypographicBounds返回的宽度为292像素而不是最大值230。

在我开始使用CTRunDelegateCallbacks代表之前,一切正常。我使用它是因为我就地渲染图像。回调只返回消息的正确宽度和高度。我没有看到什么是错的。只有当我向NSAttributedString添加大量表情时才会发生这种情况。我希望它能正确地将它设置为多行,但事实并非如此。

static void _deallocCallback (void* ref)
{
    [(id)ref release];
}

static CGFloat _ascentCallback (void *ref)
{
    UIImage* smiley = [(NSDictionary*)ref objectForKey:@"smiley"];
    return smiley.size.height; // returns 16
}

static CGFloat _widthCallback (void* ref)
{
    UIImage* smiley = [(NSDictionary*)ref objectForKey:@"smiley"];
    return smiley.size.width; // returns 16
}

- (void)renderText:(NSString*)text inRect:(CGRect)rect
{
    CGMutablePathRef path = createMyPath();
    NSAttributedString* attrString = [self _createAttributedString:text];
    // Create the frame setter and it's frame
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attrString);
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, NULL);

    // Get the height of the lines
    CFArrayRef lines = CTFrameGetLines(frame);
    CFIndex lineCount = CFArrayGetCount(lines);

    CGFloat ascent, descent, leading;

    // Get the origins of each line
    CGPoint origins[lineCount];
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins);

    // Loop through every line
    for (CFIndex i = 0; i < lineCount; i++)
    {
        // Get the typographic bounds of this line
        CTLineRef line = (CTLineRef)CFArrayGetValueAtIndex(lines, i);
        textWidth = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
        // __this returns values wider than rect in path__
    }
}

- (NSAttributedString*)_createAttributedString:(NSString*)inString
{
    // Create our default font attribute
    NSDictionary* fontAttribute = [NSDictionary dictionaryWithObject:(id)_font forKey:(NSString*)kCTFontAttributeName];

    // Create the attributed string
    NSMutableAttributedString* attributedString = [[NSMutableAttributedString alloc] init];

    CTRunDelegateCallbacks callbacks;
    callbacks.version = kCTRunDelegateVersion1;
    callbacks.getAscent = _ascentCallback;
    callbacks.getDescent = NULL;
    callbacks.getWidth = _widthCallback;
    callbacks.dealloc = _deallocCallback;

    UIImage* smiley = getSmiley(@"sad.png");

    // Do this multiple times to add a long list of smileys   
    NSDictionary* attributes = [NSDictionary dictionaryWithObjectsAndKeys:                  smiley, @"smiley", nil];
    CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, attributes);
    NSDictionary* attributeDelegate = [NSDictionary dictionaryWithObjectsAndKeys:(id)delegate, (NSString *)kCTRunDelegateAttributeName, smiley, @"smiley", nil];

    [attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" " attributes:attributeDelegate] autorelease]];

    [attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" blablabla " attributes:fontAttribute] autorelease]];

    return attributedString;
}

谢谢, 尼古拉斯

1 个答案:

答案 0 :(得分:0)

我不认为这是一个很好的解决方案,但似乎可以解决你的问题。代码中的以下行负责正确呈现/包装的文本:

[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@" " attributes:attributeDelegate] autorelease]];

CoreText似乎忽略了添加到attributedString的这些空格。 您可以通过简单地添加一个“虚拟”字符来解决这个问题,该字符实际上是渲染但由图像重叠并因此不可见。

这个字符将被Coretext视为一个新的“单词”

例如:

[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@"•" attributes:attributeDelegate] autorelease]];