iOS 16中CIAttributedTextImageGenerator多行文本生成过宽问题
iOS 16下CIAttributedTextImageGenerator多行文本宽度异常问题解决
问题重现
使用CIAttributedTextImageGenerator生成多行文本对应的CIImage时,iOS 16及以上版本出现宽度异常膨胀问题:每增加一行文本,图片宽度会大幅增长,最终生成的图片宽高比与实际文本排版严重不符(实际文本高度远大于宽度,但图片宽度反而超过高度);单行文本生成正常,iOS 15及以前版本无此问题。
用户核心实现代码:
let attributes: [NSAttributedString.Key: Any] = [ .font: font, .foregroundColor: textColor, .backgroundColor: textBackgroundColor, .shadow: shadow, .strokeColor: strokeColor, .strokeWidth: strokeWidth ] let attributedQuote = NSAttributedString(string: text, attributes: attributes) let textGenerationFilter = CIFilter(name: "CIAttributedTextImageGenerator")! textGenerationFilter.setValue(attributedQuote, forKey: "inputText") if #available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, *) { textGenerationFilter.setValue(CGFloat(0), forKey: "inputPadding") } textGenerationFilter.setValue(NSNumber(value: Double(4.0)), forKey: "inputScaleFactor") guard let textImage = textGenerationFilter.outputImage else { return nil }
问题原因
iOS 16中CIAttributedTextImageGenerator的多行文本排版计算逻辑发生变更:当未明确约束文本宽度时,滤镜错误地将每行文本的潜在最大宽度叠加,导致整体宽度无限制膨胀。而iOS 15及以前版本会自动基于文本换行后的实际最大宽度确定图片宽度。
解决方案
给NSAttributedString添加.paragraphStyle属性,通过设置preferredMaxLayoutWidth明确文本的最大宽度约束,让滤镜能正确计算多行文本的实际排版宽度。
修改步骤
- 创建并配置
NSMutableParagraphStyle:
let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping // 根据需求选择换行模式,如.byCharWrapping // 关键:设置文本的最大宽度约束 paragraphStyle.preferredMaxLayoutWidth = desiredMaxWidth // 替换为你期望的最大宽度,比如控件宽度或固定值
- 将
paragraphStyle加入属性字典:
let attributes: [NSAttributedString.Key: Any] = [ .font: font, .foregroundColor: textColor, .backgroundColor: textBackgroundColor, .shadow: shadow, .strokeColor: strokeColor, .strokeWidth: strokeWidth, .paragraphStyle: paragraphStyle // 添加此行 ]
动态计算最大宽度(可选)
如果无法提前确定desiredMaxWidth,可先计算文本在当前属性下的实际排版宽度,再将其设为preferredMaxLayoutWidth:
// 先创建不带paragraphStyle的临时富文本 let tempAttributedText = NSAttributedString(string: text, attributes: [ .font: font, .foregroundColor: textColor, .backgroundColor: textBackgroundColor, .shadow: shadow, .strokeColor: strokeColor, .strokeWidth: strokeWidth ]) // 计算文本实际排版的宽高 let tempSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) let textRect = tempAttributedText.boundingRect(with: tempSize, options: [.usesLineFragmentOrigin], context: nil) // 配置paragraphStyle let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineBreakMode = .byWordWrapping paragraphStyle.preferredMaxLayoutWidth = textRect.width // 最终创建带约束的富文本 let attributedQuote = NSAttributedString(string: text, attributes: [ .font: font, .foregroundColor: textColor, .backgroundColor: textBackgroundColor, .shadow: shadow, .strokeColor: strokeColor, .strokeWidth: strokeWidth, .paragraphStyle: paragraphStyle ])
修改后,CIAttributedTextImageGenerator会按照指定的最大宽度排版多行文本,生成的图片宽度将与文本实际排版宽度匹配,不会再出现异常膨胀。
内容的提问来源于stack exchange,提问作者SmartTree
相关产品推荐
相关产品推荐

