如何通过NSLayoutManager与文本容器实现强制分页?
强制分页实现问题:NSLayoutManager多文本容器自定义分页位置
我正在用NSLayoutManager搭配多个文本容器实现分页功能,NSTextView/UITextView实例创建后,文本能在视图间正常流动。但需求是强制指定分页位置,让内容在我设定的位置跳转到下一个容器,而且因为处理的是解析后的内容,不能向文本中插入ASCII控制字符。
尝试子类化NSLayoutManager的方案
我尝试子类化NSLayoutManager并重写textContainer(forGlyphAt:effectiveRange:)方法,代码如下:
override func textContainer(forGlyphAt glyphIndex: Int, effectiveRange effectiveGlyphRange: NSRangePointer?) -> NSTextContainer? { if glyphIndex > 100 { return self.textContainers[1] } else { return super.textContainer(forGlyphAt: glyphIndex, effectiveRange: effectiveGlyphRange) } }
预期是把第100个字形后的内容移到第二个容器,但结果不符合预期。我猜测需要子类化NSTextContainer,告知布局管理器容器已填满文本,但lineFragmentRect(forProposedRect:at:writingDirection:remaining:)方法文档太简略,找不到可用示例。现有文本显示相关文档比较陈旧,希望找到简单指定容器内容截断位置的方法。
利用exclusionPaths的可行但低效方案
有一种可行方案是用NSTextContainer.exclusionPaths占用容器剩余空间,代码如下:
let glyphIndex = layoutManager.glyphIndexForCharacter(at: 100) var rect = layoutManager.lineFragmentRect(forGlyphAt: glyphIndex, effectiveRange: nil) // 获取行范围和已用矩形 var lineRange = NSMakeRange(NSNotFound, 0) var usedRect = layoutManager.lineFragmentUsedRect(forGlyphAt: glyphIndex, effectiveRange: NSRangePointer(&lineRange)) // 计算该行剩余部分 let remainder = NSRange(location: glyphIndex, length: NSMaxRange(lineRange) - glyphIndex) var rectCount: Int = 0 var breakRects = layoutManager.rectArray(forGlyphRange: remainder, withinSelectedGlyphRange: remainder, in: textContainer1, rectCount: UnsafeMutablePointer(&rectCount)) // 创建该行剩余部分的矩形 var lineRect = breakRects!.pointee lineRect.size.width = textContainer1.size.width - lineRect.origin.x // 创建覆盖剩余区域的矩形 var coverRest = NSMakeRect(0, lineRect.origin.y + lineRect.height, textContainer1.size.width, CGFloat.greatestFiniteMagnitude) // 添加排除路径 textContainer1.exclusionPaths = [NSBezierPath(rect: lineRect), NSBezierPath(rect: coverRest)]
这个方案能达到预期效果,但计算量很大,带排除路径的文本容器性能偏低,如果应用中有数百个文本视图,会导致效率低下。
内容的提问来源于stack exchange,提问作者Antifonic
相关产品推荐
相关产品推荐

