文本包含表情符号时文本高度错误

时间:2016-02-13 08:50:44

标签: ios swift

在官方docs之后,我创建了这个函数来计算文本高度。

func calculateTextHeight(myString: String, myWidth: CGFloat, myFont: UIFont) -> CGFloat {
    let textStorage = NSTextStorage(string: myString)
    let textContainer = NSTextContainer(size: CGSize(width: myWidth, height: CGFloat.max))
    let layoutManager = NSLayoutManager()

    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)

    textStorage.addAttribute(NSFontAttributeName, value: myFont, range: NSMakeRange(0, textStorage.length))
    textContainer.lineFragmentPadding = 0
    textContainer.lineBreakMode = .ByWordWrapping

    layoutManager.glyphRangeForTextContainer(textContainer)
    return layoutManager.usedRectForTextContainer(textContainer).size.height
}

但是当文本包含表情符号时,计算出的高度是错误的。

var s = "ABCDE 12345"
print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14)))
// prints 16.7 (correct)

s = "ABCDE 12345 "
print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14)))
// prints 22.9 (should be 16.7)

这是一个错误吗?我该如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

当文本包含表情符号时,这对我有用。对于NSAttributedString字符串:

extension NSAttributedString {
    func sizeOfString(constrainedToWidth width: Double) -> CGSize {
        let framesetter = CTFramesetterCreateWithAttributedString(self)
        return CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(location: 0, length: 0), nil, CGSize(width: width, height: .greatestFiniteMagnitude), nil)
    }
}

对于String

extension String {
    func sizeOfString(constrainedToWidth width: Double, font: UIFont) -> CGSize {
        let attributes = [NSAttributedString.Key.font : font]
        let attString = NSAttributedString(string: self, attributes: attributes)
        let framesetter = CTFramesetterCreateWithAttributedString(attString)
        return CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRange(location: 0, length: 0), nil, CGSize(width: width, height: .greatestFiniteMagnitude), nil)
    }
}

答案 1 :(得分:0)

我使用了另一种方法来计算文字高度。这适用于表情符号。

static func calculateStringHeight(str: String, maxWidth: CGFloat, font: UIFont) -> CGFloat {
    return str.boundingRectWithSize(CGSizeMake(maxWidth, CGFloat.max), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil).height
}

答案 2 :(得分:-2)

我不认为这是一个错误。表情符号占用更多空间来显示。

我相信只有当你的文字中的表情符号数量太大时,这才会有所不同。 如果您尝试下面的代码,我认为结果将是相同的。

s = "ABCDE 12345 "
print(calculateTextHeight(s, myWidth: 500, myFont: UIFont.systemFontOfSize(14)))
// prints 22.9

如果要删除表情符号,可以在进行高度计算之前将其从原始文本中删除。 在这种情况下,您需要通过用其他字符替换所有表情符号来扫描原始文本,然后调用高度计算。