字符串:最大高度的最小边界

时间:2014-12-16 15:52:58

标签: xcode swift nsstring cgsize

我想计算一个矩形的最小边界,该矩形需要使用特定字体拟合字符串(多行)。

看起来应该是这样的:

FROM:

 ----------------------------------
|Sent when the application is about|
|to move from active to inactive   |
|state.                            |
 ----------------------------------

TO:

 -------------------------
|Sent when the application|
|is about to move from    |
|active to inactive state.|
 -------------------------

如您所见,高度保持不变,宽度变为必要的最小值。

最初我虽然可以使用boundingRectWithSize(约束到最大宽度)来首先获得所需的最小高度,然后调用boundingRectWithSize(约束到计算的高度)得到宽度。但是在第二步计算宽度时会产生错误的结果。它不考虑最大高度,而是简单计算单个线串的宽度。

之后我找到了一种方法来获得正确的结果,但执行此代码需要很长时间,这对我没用:

首先计算约束宽度所需的矩形:

var objectFrame = Class.sizeOfString(string, font: objectFont, width: Double(width), height: DBL_MAX)

然后是宽度:

objectFrame.size.width = Class.minWidthForHeight(string, font: objectFont, objectFrame.size.height)

使用:

class func minWidthForHeight(string: NSString, font: UIFont, height: CGFloat) -> CGFloat
{
    let deltaWidth: CGFloat = 5.0
    let neededHeight: CGFloat = rect.size.height
    var testingWidth: CGFloat = rect.size.width

    var done = false
    while (done == false)
    {
        testingWidth -= deltaWidth

        var newSize = Class.sizeOfString(string, font: font, width: Double(testingWidth), height: DBL_MAX)

        if (newSize.height > neededHeight)
        {
            testingWidth += deltaWidth
            done = true
        }
    }
    return testingWidth
}

class func sizeOfString(string: NSString, font: UIFont, width: Double, height: Double) -> CGRect
{
    return string.boundingRectWithSize(CGSize(width: width, height: height),
        options: NSStringDrawingOptions.UsesLineFragmentOrigin,
        attributes: [NSFontAttributeName: font],
        context: nil)
}

逐渐计算给定宽度的高度(每个新步长为5.0像素)并检查高度是否保持不变。一旦高度改变,它就会返回上一步的宽度。 所以现在我们有一个边界矩形,其中某个字体的字符串完全适合,没有任何浪费的空间。

但正如我所说,这需要很长的时间来计算,特别是在同时为许多不同的字符串执行时。

有更好更快的方法吗?

1 个答案:

答案 0 :(得分:-1)

所以下面的代码是我最后的问题。它非常快,对我来说效果很好。感谢@Nero让我走上正轨。

class func minFrameWidthForHeight(string: NSString, font: UIFont, rect: CGRect) -> CGFloat
{
    if (string.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).count <= 1)
    {
        return rect.size.width
    }

    var minValue: CGFloat = rect.size.width / 2
    var maxValue: CGFloat = rect.size.width

    var testingWidth: CGFloat = rect.size.width
    var lastTestingWidth: CGFloat = testingWidth
    let neededHeight: CGFloat = rect.size.height

    var newSize = rect

    while (newSize.height <= neededHeight)
    {
        lastTestingWidth = testingWidth

        testingWidth = (maxValue + minValue) / 2

        newSize = CalculationHelper.sizeOfString(string, font: font, width: Double(testingWidth), height: DBL_MAX)

        if (newSize.height <= neededHeight)
        {
            maxValue = testingWidth
        }
        else
        {
            minValue = testingWidth
        }
    }

    return lastTestingWidth
}