Строка: минимальные границы для максимальной высоты

Я хочу рассчитать минимальные границы для прямоугольника, необходимые для соответствия строки (многострочный) с определенным шрифтом.

Это должно выглядеть примерно так:

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 ответ

Решение

Так что этот код ниже - мой последний подход к вопросу под рукой. Это довольно быстро и хорошо работает для меня. Спасибо @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
}
Другие вопросы по тегам