使用Core Text绘制NSAttributedString时文本重复显示的原因排查
问题分析与解决
你遇到的文本重复问题,核心原因是每次调用drawGlyphsForGlyphRange:时,都绘制了整个NSAttributedString内容,而非当前方法指定的glyph范围对应的文本片段。同时代码存在变量名错误(使用了未定义的glyphRange,实际参数为glyphsToShow)。
解决步骤
- 修正变量名:将代码中所有
glyphRange替换为方法传入的glyphsToShow。 - 限定绘制范围:把glyph范围转换为对应的字符范围,仅绘制当前需要的文本片段,而非整个字符串。
- 规范属性调用:使用
self.textStorage替代直接引用storage,保证属性访问的正确性。
修改后的代码
- (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin { NSTextContainer *textContainer = [self textContainerForGlyphAtIndex:glyphsToShow.location effectiveRange:nil]; CGRect someRect = [self boundingRectForGlyphRange:glyphsToShow inTextContainer:textContainer]; CGFloat xPoint = someRect.origin.x + origin.x; CGFloat width = 330; CGFloat calculatedHeight = 310; CGRect adjustedRect = CGRectMake(xPoint, someRect.origin.y + origin.y, width, calculatedHeight); // 将glyph范围转换为对应的字符范围 NSRange characterRange = [self characterRangeForGlyphRange:glyphsToShow actualGlyphRange:nil]; // 创建Core Text框架,仅绘制当前需要的字符范围 CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.textStorage); CGPathRef path = CGPathCreateWithRect(adjustedRect, NULL); CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(characterRange.location, characterRange.length), path, NULL); // 翻转坐标系(需要时取消注释) CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetTextMatrix(context, CGAffineTransformIdentity); // CGContextTranslateCTM(context, 0, adjustedRect.size.height + adjustedRect.origin.y * 2); // CGContextScaleCTM(context, 1.0, -1.0); // 绘制指定范围的文本 CTFrameDraw(frame, context); // 清理Core Text资源 CFRelease(frame); CGPathRelease(path); CFRelease(frameSetter); }
额外注意事项
- 不要调用
super,否则系统默认绘制逻辑会与你的Core Text绘制叠加,再次导致文本重复。 - 若后续需要解决文本倒置问题,取消注释坐标翻转的代码即可。
内容的提问来源于stack exchange,提问作者SirRupertIII
相关产品推荐
相关产品推荐

