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

NSLayoutManager的glyphRange始终返回完整字符范围的问题求助

解决NSLayoutManager始终返回全部文本的问题

想要计算指定尺寸的NSTextContainer能容纳的文本量,但无论怎么设置容器宽高,NSLayoutManager都返回完整的字形/字符范围,只有当宽高设为0时才返回空范围。测试代码如下:

import UIKit

let height = 30
let width = 50
let text = "Dame Henrietta Barnett (1851-1936) was a social reformer and philanthropist known for her significant contributions to improving the lives of the urban poor in London during the late 19th and early 20th centuries. She is best known as the founder of Hampstead Garden Suburb, a pioneering model of urban planning that aimed to create a harmonious blend of town and country living."

let size = CGSize(width: width, height: height)
let textContainer = NSTextContainer(size: size)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = .byClipping

let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)

let font = UIFont.systemFont(ofSize: 18)
let attributes: [NSAttributedString.Key: Any] = [
    .font: font,
]

let textStorage = NSTextStorage(string: text, attributes: attributes)
textStorage.addLayoutManager(layoutManager)


let glyphRange = layoutManager.glyphRange(for: textContainer)
let characterRange = layoutManager.glyphRange(forBoundingRect: CGRect(x: 0, y: 0, width: 1, height: 1), in: textContainer)
let visibleText = (text as NSString).substring(with: characterRange)
NSLog("Visible text: \(visibleText)")

问题原因

NSLayoutManager不会自动触发文本布局计算,必须手动调用ensureLayout(for:)方法强制它完成容器内的文本布局,否则它不会判断哪些字符实际可见,直接返回全部内容。另外原代码中使用glyphRange(forBoundingRect:)传入极小矩形的方式也不合理,会导致结果偏差。

修正方案

在获取文本范围前,添加代码强制触发布局,并调整范围获取的正确方式:

import UIKit

let height = 30
let width = 50
let text = "Dame Henrietta Barnett (1851-1936) was a social reformer and philanthropist known for her significant contributions to improving the lives of the urban poor in London during the late 19th and early 20th centuries. She is best known as the founder of Hampstead Garden Suburb, a pioneering model of urban planning that aimed to create a harmonious blend of town and country living."

let size = CGSize(width: width, height: height)
let textContainer = NSTextContainer(size: size)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = .byClipping

let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)

let font = UIFont.systemFont(ofSize: 18)
let attributes: [NSAttributedString.Key: Any] = [
    .font: font,
]

let textStorage = NSTextStorage(string: text, attributes: attributes)
textStorage.addLayoutManager(layoutManager)

// 关键:强制NSLayoutManager完成容器内的文本布局计算
layoutManager.ensureLayout(for: textContainer)

// 获取容器对应的字形范围,再转换为字符范围
let glyphRange = layoutManager.glyphRange(for: textContainer)
let characterRange = layoutManager.characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil)
let visibleText = (text as NSString).substring(with: characterRange)
NSLog("Visible text: \(visibleText)")

运行修正后的代码,就能得到指定尺寸容器实际可容纳的文本内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:20:04