Строка: минимальные границы для максимальной высоты
Я хочу рассчитать минимальные границы для прямоугольника, необходимые для соответствия строки (многострочный) с определенным шрифтом.
Это должно выглядеть примерно так:
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
}