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

CATextLayer结合NSParagraphStyle时渲染与截断异常问题求助

嘿,我仔细扒了你的代码,发现几个核心问题导致了这些诡异的渲染和计算异常,咱们一步步来解决:

1. NSParagraphStyle根本没被应用到富文本中!

你在text属性的setter里创建了NSMutableParagraphStyle,设置了对齐和换行模式,但完全没把它加入到富文本的attributes字典里!这就难怪段落样式完全不起作用——你辛辛苦苦配置的样式根本没跟着文本一起传给CATextLayer。

修改text的setter,把paragraphStyle加到attributes里:

set {
    if let value = newValue {
        let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
        paragraphStyle.alignment = self.textAlignment
        paragraphStyle.lineBreakMode = self.lineBreakMode
        // 关键:把段落样式加入属性字典
        self.textLayer.string = NSMutableAttributedString(string: value, attributes: [
            .foregroundColor: self.textColor,
            .font: self.font,
            .paragraphStyle: paragraphStyle // 新增这一行
        ])
    } else {
        self.textLayer.string = nil
    }
}

2. CATextLayer的属性与段落样式冲突,截断/换行失效

你同时在lineBreakMode的setter里修改textLayer.isWrapped和textLayer.truncationMode,但当CATextLayer使用**富文本(NSAttributedString)**时,这些属性会被富文本里的NSParagraphStyle覆盖!所以你之前的操作等于做了无用功,还可能导致冲突。

修改lineBreakMode的setter,只需要更新段落样式并刷新富文本即可,不需要直接修改CATextLayer的属性:

public var lineBreakMode: NSLineBreakMode {
    get {
        return _lineBreak
    }
    set {
        _lineBreak = newValue
        // 只要更新文本的段落样式,然后重新设置text即可触发更新
        if let currentText = self.text {
            self.text = currentText // 触发setter重新生成带新段落样式的富文本
        }
    }
}

同理,textAlignment的setter也应该改成这种方式——直接修改CATextLayer的alignmentMode对富文本无效,必须通过更新段落样式来实现。

3. sizeOfTextThatFits总是返回21的原因

这个方法里的CTFramesetter计算逻辑有问题:

  • 你没有把正确的段落样式传给CTFramesetter(因为之前富文本里就没包含),导致CTLine的高度计算异常;
  • 初始的yOffset是0,但CTLine的ascent + descent + leading是单行的高度,当文本为空或者样式错误时,可能只算出单行默认高度(刚好21,对应系统字体17号的行高)。

另外,你在layoutSubviews里用boundingRect计算尺寸时,也需要确保传入的富文本包含正确的段落样式。修改后的layoutSubviews可以简化成这样:

internal override func layoutSubviews() {
    super.layoutSubviews()
    guard let attrString = self.textLayer.string as? NSAttributedString else {
        self.textLayer.frame = .zero
        return
    }
    // 用正确的富文本计算尺寸
    let rect = attrString.boundingRect(with: self.bounds.size, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
    self.textLayer.contentsScale = UIScreen.main.scale
    self.textLayer.rasterizationScale = UIScreen.main.scale
    self.textLayer.frame = CGRect.centerRect(rect, in: self.bounds)
    self.textLayer.backgroundColor = UIColor.lightGray.cgColor
}

最后验证效果

把这些修改做完后,你会发现:

  • 段落样式的换行、对齐、截断都正常生效了;
  • 文本尺寸计算不再异常;
  • 最后一行的间距也会因为正确的段落样式而恢复正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:57:36