You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Objective-C中用Quartz 2D实现PDF评论区文本分行排版的方法

解决Core Graphics PDF评论区逐行文本控制问题

看起来你现在的问题是没法对评论区的每一行文本单独控制,对吧?我看了你的代码,问题出在你把整个评论文本一次性绘制到一个大的rect里了——系统自动帮你换行,但这样你没法精准控制每一行的位置、样式,也没法和你手动画的那些横线对应上。下面给你两种实用的解决方案:

方案一:手动拆分文本逐行绘制

这种方法适合简单场景,能精准把每一行文本对齐你画的横线,还能单独控制每一行的内容和样式:

// 你的原始评论文本
NSString *commentText = @"helo how are you. i am tuna string. i have so many friends. helllo i am working.here is my paragraph writing";
// 假设fontName2是你的字体名称,这里初始化字体
UIFont *newfont = [UIFont fontWithName:fontName2 size:7]; 
// 横线之间的间距(你画的横线从155到170,间距15)
CGFloat lineSpacing = 15;
// 第一行文本的起始Y坐标
CGFloat currentY = 146;
// 文本区域的宽度(横线从20到295,文本从62开始,所以宽度是295-62=233)
CGFloat textLineWidth = 295 - 62;
// 用可变字符串存储剩余未绘制的文本
NSMutableString *remainingText = [commentText mutableCopy];

// 逐行处理文本
while (remainingText.length > 0 && currentY <= 200) { // 200是最后一条横线的Y坐标,防止超出范围
    // 计算当前行能容纳的文本范围
    CGRect textBounds = [remainingText boundingRectWithSize:CGSizeMake(textLineWidth, CGFLOAT_MAX) 
                                                    options:NSStringDrawingUsesLineFragmentOrigin 
                                                 attributes:@{NSFontAttributeName: newfont} 
                                                    context:nil];
    // 找到第一个换行的空格位置,避免单词被截断
    NSRange spaceRange = [remainingText rangeOfString:@" " options:0 range:NSMakeRange(0, textBounds.size.width)];
    NSInteger lineEndIndex = (spaceRange.location != NSNotFound) ? spaceRange.location : remainingText.length;
    
    // 截取当前行的文本
    NSString *currentLineText = [remainingText substringToIndex:lineEndIndex];
    // 绘制当前行到对应位置
    CGRect lineRect = CGRectMake(62, currentY, textLineWidth, lineSpacing);
    [currentLineText drawInRect:lineRect withFont:newfont lineBreakMode:NSLineBreakByClipping alignment:NSTextAlignmentLeft];
    
    // 更新剩余文本和下一行的Y坐标
    [remainingText deleteCharactersInRange:NSMakeRange(0, lineEndIndex)];
    currentY += lineSpacing;
}

方案二:用NSAttributedString + 布局管理器(更灵活)

如果需要更复杂的样式控制(比如某一行加粗、变色),或者要处理更复杂的文本布局,推荐用Text Kit的组件来实现,能更精准地控制每一行:

NSString *commentText = @"helo how are you. i am tuna string. i have so many friends. helllo i am working.here is my paragraph writing";
UIFont *newfont = [UIFont fontWithName:fontName2 size:7];

// 创建带属性的文本,这里可以给不同段落/行设置不同样式
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:commentText attributes:@{
    NSFontAttributeName: newfont,
    NSForegroundColorAttributeName: [UIColor blackColor]
}];
// 比如给某一行设置加粗:
// [attributedText addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:7] range:NSMakeRange(0, 10)];

// 初始化Text Kit组件
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(295-62, CGFLOAT_MAX)];
textContainer.lineFragmentPadding = 0; // 去掉默认的内边距
[layoutManager addTextContainer:textContainer];

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedText];
[textStorage addLayoutManager:layoutManager];

// 逐行绘制文本
NSUInteger glyphIndex = 0;
CGFloat currentY = 146;
CGFloat lineSpacing = 15;

while (glyphIndex < layoutManager.numberOfGlyphs && currentY <= 200) {
    CGRect lineFragmentRect;
    // 获取当前行的字形范围和位置
    NSRange lineGlyphRange = [layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRect:&lineFragmentRect];
    // 调整行的位置到你的横线对应位置
    CGPoint drawPoint = CGPointMake(62, currentY);
    // 绘制当前行
    [layoutManager drawGlyphsForGlyphRange:lineGlyphRange atPoint:drawPoint];
    
    // 更新索引和Y坐标
    glyphIndex = NSMaxRange(lineGlyphRange);
    currentY += lineSpacing;
}

为什么原来的方法不行?

你之前用[commentText drawInRect:...]把整个文本放进一个大rect,系统会自动换行,但这种方式是“黑盒”的——你没法控制每一行的具体位置,也没法单独修改某一行的样式,更没法保证文本和你手动画的横线精准对齐。上面的两种方法都是把文本拆分成单独的行,让你能完全掌控每一行的绘制。

内容的提问来源于stack exchange,提问作者Jezebel Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:42:16