CTFramesetterSuggestFrameSizeWithConstraints,剪切属性返回零高度

H! 我正在编写带有子视图剪切function的te​​xtview。 我们的想法是让所有文字都围绕所有子视图绘制。 问题是获得它的内容高度。

由于缺少文档,我决定CTFramesetterSuggestFrameSizeWithConstraints的属性字典与CTFramesetterCreateFrame的属性字典相同。

这是我的裁剪路径代码:

-(CFDictionaryRef)clippingPathsDictionary{ if(self.subviews.count==0)return NULL; NSMutableArray *pathsArray = [[NSMutableArray alloc] init]; CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, 1, -1); transform = CGAffineTransformTranslate(transform, 0, -self.bounds.size.height); for (int i=0; i<self.subviews.count; i++) { UIView *clippingView = self.subviews[i]; CGPathRef clipPath = CGPathCreateWithRect(clippingView.frame, &transform); NSDictionary *clippingPathDictionary = [NSDictionary dictionaryWithObject:(__bridge id)(clipPath) forKey:(__bridge NSString *)kCTFramePathClippingPathAttributeName]; [pathsArray addObject:clippingPathDictionary]; CFRelease(clipPath); } int eFrameWidth=0; CFNumberRef frameWidth = CFNumberCreate(NULL, kCFNumberNSIntegerType, &eFrameWidth); int eFillRule = kCTFramePathFillEvenOdd; CFNumberRef fillRule = CFNumberCreate(NULL, kCFNumberNSIntegerType, &eFillRule); int eProgression = kCTFrameProgressionTopToBottom; CFNumberRef progression = CFNumberCreate(NULL, kCFNumberNSIntegerType, &eProgression); CFStringRef keys[] = { kCTFrameClippingPathsAttributeName, kCTFramePathFillRuleAttributeName, kCTFrameProgressionAttributeName, kCTFramePathWidthAttributeName}; CFTypeRef values[] = { (__bridge CFTypeRef)(pathsArray), fillRule, progression, frameWidth}; CFDictionaryRef clippingPathsDictionary = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); return clippingPathsDictionary;} 

我用它来绘制文本,它工作正常。 这是我的绘图代码:

 - (void)drawRect:(CGRect)rect{ CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, 1, -1); transform = CGAffineTransformTranslate(transform, 0, -rect.size.height); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextConcatCTM(context, transform); CFAttributedStringRef attributedString = (__bridge CFAttributedStringRef)self.attributedString; CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(attributedString); CFDictionaryRef attributesDictionary = [self clippingPathsDictionary]; CGPathRef path = CGPathCreateWithRect(rect, &transform); CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, self.attributedString.length), path, attributesDictionary); CFRelease(path); CFRelease(attributesDictionary); CTFrameDraw(frame, context); CFRelease(frameSetter); CFRelease(frame); CGSize contentSize = [self contentSizeForWidth:self.bounds.size.width]; CGPathRef highlightPath = CGPathCreateWithRect((CGRect){CGPointZero, contentSize}, &transform); CGContextSetFillColorWithColor(context, [UIColor colorWithRed:.0 green:1 blue:.0 alpha:.3].CGColor); CGContextAddPath(context, highlightPath); CGContextDrawPath(context, kCGPathFill); CFRelease(highlightPath); 

}

这是结果:

绘图结果 这正是我所期待的!

最后,这是检查高度的代码:

 -(CGSize)contentSizeForWidth:(float)width{ CFAttributedStringRef attributedString = (__bridge CFAttributedStringRef)self.attributedString; CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(attributedString); CFDictionaryRef attributesDictionary = [self clippingPathsDictionary]; CGSize size = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0, self.attributedString.length), attributesDictionary, CGSizeMake(width, CGFLOAT_MAX), NULL); NSLog(@"%s: size = %@",__PRETTY_FUNCTION__, NSStringFromCGSize(size)); CFRelease(attributesDictionary); CFRelease(frameSetter); return size; 

}

输出看起来像这样:

 Core Text Demo[2222:a0b] -[DATextView contentSizeForWidth:]: size = {729.71484, 0} 

有人有任何解决方案吗? 感谢关注:)

在我看来,这似乎是一个iOS7错误。 我一直在修补,在iOS6下, CTFramesetterSuggestFrameSizeWithConstraints返回一个高度大于0的大小。在iOS7下的相同代码返回高度0。

CTFramesetterSuggestFrameSizeWithConstraints以其错误和未记录的行为而闻名。 例如,由于CTFramesetterSuggestFrameSizeWithConstraints执行的计算不正确, CTFramesetterSuggestFrameSizeWithConstraints下的代码返回的高度不正确,计算中忽略了最后一行。 这是您在iOS6下运行的代码:

在此处输入图像描述

您应该在以下url打开有关这些问题的错误报告以及请求文档增强function: https : //bugreport.apple.com

在iOS7下,使用TextKit,您可以更快更优雅地实现相同的结果:

 @interface LeoView : UIView @property (nonatomic, assign) UIEdgeInsets contentInset; @property (nonatomic, retain) NSLayoutManager* layoutManager; @property (nonatomic, retain) NSTextContainer* textContainer; @property (nonatomic, retain) NSTextStorage* textStorage; @end @implementation LeoView -(void)awakeFromNib { //Leo: This should not be done here. Just for example. You should do this in the init. self.textStorage = [[NSTextStorage alloc] initWithString:@"Lorem ipsum dolor [...]"]; self.layoutManager = [[NSLayoutManager alloc] init]; [self.textStorage addLayoutManager:self.layoutManager]; self.textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size]; [self.layoutManager addTextContainer:self.textContainer]; } - (void)layoutSubviews { [super layoutSubviews]; //Leo: At this point the user may have set content inset, so need to take into account. CGSize size = self.bounds.size; size.width -= (self.contentInset.left + self.contentInset.right); size.height -= (self.contentInset.top + self.contentInset.bottom); self.textContainer.size = size; NSMutableArray* exclussionPaths = [NSMutableArray new]; for (UIView* subview in self.subviews) { if(subview.isHidden) continue; CGRect frame = subview.frame; //Leo: If there is content inset, need to compensate. frame.origin.y -= self.contentInset.top; frame.origin.x -= self.contentInset.left; [exclussionPaths addObject:[UIBezierPath bezierPathWithRect:frame]]; } self.textContainer.exclusionPaths = exclussionPaths; [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { [self.layoutManager drawGlyphsForGlyphRange:[self.layoutManager glyphRangeForTextContainer:self.textContainer] atPoint:CGPointMake(self.contentInset.left, self.contentInset.top)]; //Leo: Move used rectangle according to content inset. CGRect usedRect = [self.layoutManager usedRectForTextContainer:self.textContainer]; usedRect.origin.x += self.contentInset.left; usedRect.origin.y += self.contentInset.top; CGAffineTransform transform = CGAffineTransformIdentity; transform = CGAffineTransformScale(transform, 1, -1); transform = CGAffineTransformTranslate(transform, 0, -rect.size.height); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextConcatCTM(context, transform); CGPathRef highlightPath = CGPathCreateWithRect(usedRect, &transform); CGContextSetFillColorWithColor(context, [UIColor colorWithRed:.0 green:1 blue:.0 alpha:.3].CGColor); CGContextAddPath(context, highlightPath); CGContextDrawPath(context, kCGPathFill); CFRelease(highlightPath); } @end 

以下是contentInset设置为UIEdgeInsetsMake(20, 200, 0, 35)

在此处输入图像描述

我用你的代码在文本周围绘制绿色矩形。