1

这是示例代码块

let attrString = NSAttributedString(string: "very long string goes here...") // very long string
var currentTextPos = 400 // current text position. ex. 400

let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
let path = CGPath(rect: UIScreen.main.bounds, transform: nil)
let ctFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(currentTextPos, 0), path, nil)

// draw frame with CTFrameDraw() function later

举个例子,假设我们有很长的属性字符串,我们想从 400 索引开始绘制一个帧。

要绘制下一帧,我们可以计算当前帧中有多少字符并绘制它。以下是如何实现它的示例:

// Get the length of string which fits in current CTFrame object
let frameLength = CTFrameGetVisibleStringRange(ctFrame).length // ex. frameLength == 95
// Append this to our currentTextPos variable
currentTextPos += frameLength // 400 + 95 = 495 . This is our next frame starting position
// Create another frame starting from 495 position
let nextFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(currentTextPos, 0), path, nil)

在这种情况下,我们能够获得下一个CTFrame对象。这很容易实现,因为CTFramesetterCreateFrame将用一条线填充整个帧,直到它到达帧的末尾或直到字符串的末尾。所以很容易获得下一个CTFrame起始位置。

主要问题是如何获取先前的CTFrame对象?还是之前的CTFrame起始位置?

想象一下,我们只有当前的文本位置,没有别的。从字符串的开头到结尾分别计算每个帧的起始位置并将其缓存在某处也很容易,但是如果我们能够更改属性字符串字体大小或类似的东西,这将改变CTFrame整个. 更改字体大小后,应从与更改字体大小CTFrame之前相同的 currentTextPosition 绘制对象,换句话说,更改字体大小不应影响当前帧的起始位置。

4

1 回答 1

0

CTFramesetter不管理 的列表,CTFrame并且框架本身是不可变的。

框架管理是我们的责任,所以如果文本源有任何变化,即。属性字符串,我们必须从头开始重新生成所有帧,因为这是 framesetter 进展的唯一方式 - 没有反向推进模式。幸运的是,这个过程被证明很快并且可以在后台线程中完成。

如果只需要在当前位置之前的文本范围有一个框架(例如,屏幕外绘图等)(如果,例如,从当前位置绘制在屏幕上),则可以使用类似的方法创建该框架以下扩展

extension CTFramesetter {
    func prevFrame(position: Int) -> CTFrame {

        let size = CTFramesetterSuggestFrameSizeWithConstraints(self,
            CFRange(location: 0, length: position), nil,
            CGSize(width: UIScreen.main.bounds.width, height: CGFloat.greatestFiniteMagnitude), nil)

        let path = CGPath(rect: CGRect(origin: .zero, size: size), transform: nil)
        return CTFramesetterCreateFrame(self, CFRangeMake(0, position), path, nil)
    }
}

当然它不是通用的,因为布局路径可能不同,属性可能不同,但对于主题开始问题中提供的简化条件,它可以使用。

于 2020-04-18T11:15:52.683 回答