CTFrame 有时为空,具体取决于 UIFont pointSize

CTFrame is sometimes empty depending on the UIFont pointSize

我正在尝试使用 Core Text 在 CGContext 中绘制属性字符串。我有一个有趣的问题,它适用于某些字体大小,但不适用于其他字体大小。 CTFrame 有时为空 - visible string range = (0,0) - 这意味着框架设置器无法布置文本。我发现这是因为路径太小而无法在其中绘制文本。如果我在这种情况下将 10 添加到高度,那么它就可以工作。

知道为什么会这样吗?我怎样才能得到它需要的大小,既不小也不大?

let fontSize: CGFloat = 191 //FIXME: 190 and 192 work, why not 191?
let attributedString = NSAttributedString(string: "Hello", attributes: [.font: UIFont.systemFont(ofSize: fontSize)])
let textSize = attributedString.size()

let rect = CGRect(origin: .zero, size: CGSize(width: 4000, height: 3000))
let positionX = rect.width - ceil(textSize.width) //right edge of rect
let path = CGPath(rect: CGRect(x: positionX, y: 0, width: ceil(textSize.width), height: ceil(textSize.height)/* + 10*/), transform: nil)

let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attributedString.length), path, nil)
print(frame)

这里 fontSize == 190:

的结果
<CTFrame: 0x600000598a80>{visible string range = (0, 5), path = <CGPath 0x600001f8fc50>, attributes = (null), lines = (
    "<CTLine: 0x60000039a670>{run count = 1, string range = (0, 5), width = 408.574, A/D/L = 180.908/45.8301/0, glyph count = 5, runs = (\n\n<CTRun: 0x7fdde391adf0>{string range = (0, 5), string = \"Hello\", attributes = {\n    NSFont = \"<UICTFont: 0x7fdde1c0fc20> font-family: \\".SFUIDisplay\\"; font-weight: normal; font-style: normal; font-size: 190.00pt\";\n}}\n\n)\n}"
)}

这里 fontSize == 191:

的结果
<CTFrame: 0x600003e56bc0>{visible string range = (0, 0), path = <CGPath 0x60000240f0c0>, attributes = (null), lines = (
)}

正在回答 phone 对于格式问题,我们深表歉意。使用 CTFramesetterSuggestFrameSizeWithConstraints 而不是代码中的 textSize。

 let attri = NSAttributedString(string: str, attributes: self.attributes(str: str, font: ft))
 let frameSetter = CTFramesetterCreateWithAttributedString((attri as CFAttributedString))
 var fitRange = CFRangeMake(0, 0)
 var fitRange = CFRangeMake(0, 0)
 let suggested = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0,attri.length), nil, CGSize(width:bounds.width,height:.greatestFiniteMagnitude), &fitRange)
 path.addRect(CGRect(x: 0, y: 0, width: ceil(max(suggested.width, self.bounds.width)), height: ceil(max(suggested.height, self.bounds.height))))
 let ctFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0,attri.length), path, nil)