iOS UITableView与dynamic文本和图像一起渲染(NSAttributedString +图像)

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

我一直在四处寻找,我已经尝试了一些方法。 我最初的想法是使用UIWebView。 我能够创build一个示例应用程序与每行一个UIWebView,甚至与一些“聪明的”NSCache预渲染的单元格性能不是很好,再加上我不得不处理UIWebView JavaScriptcallback找出内容何时正确加载。

我的第二个尝试是覆盖drawRect一个新的UITableViewCell。 在drawRect方法中,我使用NSAttributedString和NSSelectorFromString来设置每种内容(常规文本,粗体,斜体,不同颜色,图像)的范围。 为了适应我使用CTRunDelegateCallbackscallback(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#

最后有两个问题:

  • 这是最好的方法,我可以使这个performance好吗? 我想知道是否为每个滚动的每个单元格调用drawRect不会很麻烦 – 有什么我可以提前做的吗? 我已经玩了一段时间了,但仍然是一个很大的滞后 – 但我还没有试图caching单独的线程中的每一行,并使用cellForRowAtIndexPath(虽然可能会超过内存使用);

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

—添加更多信息

在我的drawRect创build所有内容(string和图像)之后,我试图使用boundingRectWithSize来获得适当的高度:

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

这工作正常,如果它只是文本,但是当我添加图像标志符号的内容,它不能正确计算高度…

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

从故事板检索自定义原型单元格高度?

至于性能,你有没有运行Time Profiler来缩小造成滞后的原因?

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

相反,我在Core Text中find了一个较低级别的API,它满足了所有的要求,而且是完全正确的。 我为这个问题创build了一个类别。 玩得开心用它! 🙂

头文件:

 #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 
Interesting Posts