iOS UITableView,动态文本和图像一起渲染(NSAttributedString + images)

时间:2013-05-16 11:25:40

标签: ios uitableview drawrect nsattributedstring

我的问题是:我在iOS应用程序中有动态内容(例如twits - 虽然这不是推特应用程序),包括文本和图像(主要是图标/表情符号和缩略图)。我想在表格行中同时渲染文本和图像。这里的主要困难是每一行都有不同的大小(使缓存更难),我需要动态计算图像大小以适应每个图像出现的文本(我可以有20个表情符号一个接一个+文本+更多表情符号+等)。

我一直在四处寻找,我尝试了一些方法。我最初的想法是使用UIWebView。我能够创建一个每行一个UIWebView的示例应用程序,即使有一些“智能”NSCache用于预渲染单元格,性能也不是很好,而且我不得不处理UIWebView javascript回调以确定内容是否正确加载

我的第二次尝试是覆盖新的UITableViewCell的drawRect。在drawRect方法中,我使用NSAttributedString和NSSelectorFromString来设置每种内容的范围(常规文本,粗体,斜体,不同颜色,图像)。为了适应图像我正在使用CTRunDelegateCallbacks回调(getAscent,getDescent,getWidth)。像这样:

            CTRunDelegateCallbacks callbacks;
            callbacks.version = kCTRunDelegateVersion1;
            callbacks.getAscent = ascentCallback;
            callbacks.getDescent = descentCallback;
            callbacks.getWidth = widthCallback;

            CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (__bridge void *)imgAttr); // img Attr is a Dictionary with all image info

有关此方法的详细信息,请查看此优秀帖子:http://www.raywenderlich.com/4147/how-to-create-a-simple-magazine-app-with-core-text#

最后,有两个问题:

  • 这是最好的方法,我能以良好的性能做到这一点吗?我想知道是否必须为每个卷轴为每个单元调用drawRect不会很麻烦 - 有什么我可以提前做的吗?我已经玩了一段时间了,它仍然是一个很大的滞后 - 但我还没有尝试在单独的线程中缓存每一行并在cellForRowAtIndexPath中使用它(尽管可能超出内存使用);

  • 我无法找出获得每个tableview单元格行高的最佳方法。在NSAttributedString正确处理了我的所有内容后,如何知道drawRect函数使用的高度?

---添加更多信息

在我的drawRect创建所有内容(字符串和图像)后,我正在尝试使用boundingRectWithSize来获得正确的高度:

CGRect frame = [self.attString boundingRectWithSize:CGSizeMake(320, 10000) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingUsesDeviceMetrics context:nil];

如果它只是文本,这可以正常工作,但是当我将图像字形添加到内容时,它不能正确计算高度......

2 个答案:

答案 0 :(得分:3)

我遇到了同样的问题并且今天解决了它。我正在使用CTRunDelegateCallbacks在文本之间绘制自定义对象,但boundingRectWithSize:options:context:没有给出正确的高度。 (它忽略了我的自定义对象)。

相反,我在Core Text中找到了一个较低级别的API,它满足所有要求并且完全正确。我为该问题创建了一个类别。玩得开心吧! : - )

标题文件:

#import <Foundation/Foundation.h>

@interface NSAttributedString (boundsForWidth)

- (CGRect)boundsForWidth:(float)width;

@end

实施文件:

#import "NSAttributedString+boundsForWidth.h"
#import <CoreText/CoreText.h>

@implementation NSAttributedString (boundsForWidth)

- (CGRect)boundsForWidth:(float)width
{
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self);

    CGSize maxSize = CGSizeMake(width, 0);

    CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, maxSize, nil);

    CFRelease(framesetter);

    return CGRectMake(0, 0, ceilf(size.width), ceilf(size.height));
}

@end

答案 1 :(得分:2)

这篇文章可能会让你朝着正确的方向计算行高:

Retrieve custom prototype cell height from storyboard?

至于性能,您是否运行Time Profiler来缩小导致延迟的原因?