iOS脚本类字体文本尺寸计算异常,如何获取正确宽度?
解决UITextView脚本类字体文本尺寸计算不准确的问题
脚本类字体(如Radicalis、Allura)的字形常存在超出标准排版边界的部分,UITextView自带的sizeThatFits(_:)方法仅基于文本的排版基线计算尺寸,无法覆盖这类特殊字形的视觉范围,导致字母被截断。以下是几种可靠的解决方式:
1. 用CoreText计算精确视觉尺寸
CoreText会完整考虑字形的所有视觉元素,包括超出基线的部分,能返回最准确的文本尺寸。实现代码如下:
func getExactTextSize(text: String, font: UIFont, maxWidth: CGFloat = .greatestFiniteMagnitude) -> CGSize { let attrString = NSAttributedString(string: text, attributes: [.font: font]) let frameSetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString) // 获取约束下的建议尺寸 let suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints( frameSetter, CFRange(location: 0, length: attrString.length), nil, CGSize(width: maxWidth, height: .greatestFiniteMagnitude), nil ) // 向上取整避免小数尺寸导致的截断 return CGSize(width: ceil(suggestedSize.width), height: ceil(suggestedSize.height)) }
使用时直接用这个方法获取尺寸,再设置UITextView的frame即可。
2. 调整UITextView的容器内边距
如果不想引入CoreText,可通过调整textContainerInset和lineFragmentPadding给特殊字体预留额外空间:
// 给上下边距增加预留空间,数值可根据字体调整 textView.textContainerInset = UIEdgeInsets(top: 6, left: 0, bottom: 6, right: 0) // 移除左右默认内边距,避免额外宽度占用 textView.textContainer.lineFragmentPadding = 0
这种方式属于临时补救,不同字体需要调整不同的内边距数值,通用性较弱。
3. 结合两种方式优化
先通过CoreText获取精确尺寸,再给UITextView设置frame时,额外增加少量内边距作为缓冲,确保极端情况下内容也不会被截断:
let exactSize = getExactTextSize(text: yourText, font: selectedFont) textView.frame = CGRect(x: textView.frame.origin.x, y: textView.frame.origin.y, width: exactSize.width, height: exactSize.height) textView.textContainerInset = UIEdgeInsets(top: 2, left: 0, bottom: 2, right: 0)
内容的提问来源于stack exchange,提问作者Dipesh Patel
相关产品推荐
相关产品推荐

