解决这个问题并遵循几位海报的许多不同答案,我已经为正确文本大小的所有强大问题实施了一个解决方案,对我来说CTFramesetterSuggestFrameSizeWithConstraints 无法正常工作,所以我们需要使用CTFramesetterCreateFrame然后测量该帧的大小,(这是UIFont 扩展)这是swift 100%
参考文献
CTFramesetterSuggestFrameSizeWithConstraints sometimes returns incorrect size?
How to get the real height of text drawn on a CTFrame
Using CFArrayGetValueAtIndex in Swift with UnsafePointer (AUPreset)
func sizeOfString (string: String, constrainedToWidth width: Double) -> CGSize {
let attributes = [NSAttributedString.Key.font:self]
let attString = NSAttributedString(string: string,attributes: attributes)
let framesetter = CTFramesetterCreateWithAttributedString(attString)
let frame = CTFramesetterCreateFrame(framesetter,CFRange(location: 0,length: 0),CGPath.init(rect: CGRect(x: 0, y: 0, width: width, height: 10000), transform: nil),nil)
return UIFont.measure(frame: frame)
}
然后我们测量我们的 CTFrame
static func measure(frame:CTFrame) ->CGSize {
let lines = CTFrameGetLines(frame)
let numOflines = CFArrayGetCount(lines)
var maxWidth : Double = 0
for index in 0..<numOflines {
let line : CTLine = unsafeBitCast(CFArrayGetValueAtIndex(lines, index), to: CTLine.self)
var ascent : CGFloat = 0
var descent : CGFloat = 0
var leading : CGFloat = 0
let width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading)
if(width > maxWidth) {
maxWidth = width
}
}
var ascent : CGFloat = 0
var descent : CGFloat = 0
var leading : CGFloat = 0
CTLineGetTypographicBounds(unsafeBitCast(CFArrayGetValueAtIndex(lines, 0), to: CTLine.self), &ascent, &descent, &leading)
let firstLineHeight = ascent + descent + leading
CTLineGetTypographicBounds(unsafeBitCast(CFArrayGetValueAtIndex(lines, numOflines - 1), to: CTLine.self), &ascent, &descent, &leading)
let lastLineHeight = ascent + descent + leading
var firstLineOrigin : CGPoint = CGPoint(x: 0, y: 0)
CTFrameGetLineOrigins(frame, CFRangeMake(0, 1), &firstLineOrigin);
var lastLineOrigin : CGPoint = CGPoint(x: 0, y: 0)
CTFrameGetLineOrigins(frame, CFRangeMake(numOflines - 1, 1), &lastLineOrigin);
let textHeight = abs(firstLineOrigin.y - lastLineOrigin.y) + firstLineHeight + lastLineHeight
return CGSize(width: maxWidth, height: Double(textHeight))
}