字符串容器大小,计算给定最大高度的最小宽度

时间:2015-02-07 10:51:56

标签: objective-c string cocoa swift

对符合格式化字符串的大多数需求需要计算容器的高度,给定字符串的最大宽度。 cocoa API中的这些函数反映了这种情况。

NSTextField.sizeThatFits()

此方法将最大宽度设为固定,并调整高度以包含文本。

你如何与上述相反 - 给定一个高度限制,计算最小的宽度来封闭文本?

我首先想到的一种方法是首先通过将单行文本的面积除以所需高度来创建估计值,以获得估计的宽度。但这总是高估了身高,因为单词会包裹,沿着其他单词推动。算法的下一个阶段,取这个多余的高度并将其添加到假想矩形的末端,直到最大高度限制被打破,给出宽度的上下估计。算法的最后部分收敛于一种二分搜索,直到达到某个像素容差。我会尽可能地发布这个答案。

我觉得必须有更好的方法吗? (ObjC或Swift)

2 个答案:

答案 0 :(得分:0)

如何获取属性字符串的高度和宽度,然后查找字符串高度符合高度限制的次数,然后将字符串的宽度除以如下:

NSAttributedString *myString = /*an attributed string*/
NSSize rawSize = myString.size; /*imagine a size of h20w100*/
int heightLimit = 40; /*example height limit*/
int linesAvailable = heightLimit/rawSize.height; /*gets the max number of lines available for the text*/
int neededWidth = rawSize.width/linesAvailable; /*gets the width of field needed to fit the whole text in the available height*/
NSSize fieldSize = NSMakeSize(needeWidth,heightLimit);

这应该为您提供一个文本字段,其宽度正确以适应字符串的高度(在这种情况下,您将有2行可用,因此需要宽度为50)。

答案 1 :(得分:0)

计算给定最大高度的文字宽度:

以下代码对我来说效果很好,当公差设置为5时,它会计算3或4个尺寸。您可以替换为您喜欢的任何尺寸计算功能,例如:你上面的功能。根据您的要求设置公差。希望这会有所帮助 - 它绝对可以优化(如果你更多地牺牲可读性)

func setLabelSize {

    var max_height = CGFloat(200) //This is the maximum height
    var big_float = CGFloat(99999)
    var width_estimate = big_float //This is the initial estimate

    var old_size = label.sizeThatFits(NSSize(width: width_estimate, height: big_float))

    width_estimate = old_size.width * old_size.height / max_height

    var new_size = label.sizeThatFits(NSSize(width: width_estimate, height: big_float))
    var old_width_estimate = width_estimate

    //first estimate will always be short, so loop until upper bound is found
    while (new_size.height < max_height) {
        old_width_estimate = width_estimate
        old_size = new_size

        var surpless_area = (new_size.height - max_height) * width_estimate
        width_estimate += (surpless_area / new_size.height) 

        new_size = label.sizeThatFits(NSSize(width: width_estimate, height: big_float))
        println("estimate: \(width_estimate) old_estimate: \(old_width_estimate) new_size: \(new_size) old_size: \(old_size)")
    }

    //value is inbetween old_width_estimate and width_estimate
    //width_estimate should be lower estimate, old should be higher
    var upper_estimate = old_width_estimate
    var lower_estimate = width_estimate
    var upper_estimate_size = old_size
    var tolerance = CGFloat(5)

    while(true) {

        var diff = (upper_estimate - lower_estimate) / 2
        println("upper: \(upper_estimate) lower: \(lower_estimate) diff: \(diff)")
        if diff <= tolerance {
            break
        } else {
            var half_estimate = lower_estimate + diff
            new_size = label.sizeThatFits(NSSize(width: half_estimate, height: big_float))
            if new_size.height>max_height {
                lower_estimate = half_estimate
            } else {
                upper_estimate = half_estimate
                upper_estimate_size = new_size
            }
        }
    }

    println("Final size \(upper_estimate_size)")

    label.frame.size = upper_estimate_size
}
相关问题