NSLayoutManager的usedRect在NSAttributedString无自身字体属性时返回错误矩形的问题
NSLayoutManager的usedRect在NSAttributedString无自身字体属性时返回错误矩形的问题
最近我在做一个UILabel的子类,核心需求是要检测NSAttributedString里的点击区域,无奈因为项目里的一些限制,完全没法用UITextView来替代。查了不少思路后,我用NSLayoutManager、NSTextContainer加NSTextStorage这套组合来计算文本的边界框textBoundingBox,本来大部分场景都跑通了,结果遇到个头疼的坑——当我的NSAttributedString没有显式设置自身的字体属性时,layoutManager.usedRect返回的矩形完全不对!
其实这个问题很多开发者都碰到过,本质原因是:当NSAttributedString没有自带字体属性时,NSLayoutManager会自动 fallback 到系统默认字体(一般是12号的San Francisco或者Helvetica),但这个默认字体和你UILabel上设置的字体大概率不匹配,自然就导致计算出来的usedRect尺寸偏差了。
给你几个亲测有效的解决办法:
- 给
NSAttributedString的所有内容显式设置字体属性,哪怕和UILabel的字体完全一致,确保NSLayoutManager能拿到正确的字体参数来计算边界 - 在创建
NSTextStorage之前,先把UILabel的默认字体同步到NSAttributedString上,补全缺失的字体属性 - 可以先通过
NSString的boundingRect(with:options:attributes:context:)方法,用UILabel的字体先算出基准尺寸,再和layoutManager.usedRect的结果做校验修正
这里给你贴个简单的代码示例,用来补全NSAttributedString的字体属性:
// 假设label是你的UILabel子类实例 let baseFont = label.font ?? UIFont.systemFont(ofSize: 17) let mutableAttrString = NSMutableAttributedString(attributedString: yourOriginalAttrString) // 给整个字符串范围补全字体属性 mutableAttrString.addAttribute(.font, value: baseFont, range: NSRange(location: 0, length: mutableAttrString.length)) // 用补全后的字符串初始化NSTextStorage let textStorage = NSTextStorage(attributedString: mutableAttrString)
这样处理之后,再去调用layoutManager.usedRect(for: textContainer),应该就能得到正确的文本边界框了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

