【问题标题】:First two lines of NSString with width and font given给定宽度和字体的前两行 NSString
【发布时间】:2011-12-12 11:10:43
【问题描述】:

我有一个很长的 NSStringUIFont 和想要的 width。我只想得到符合给定 UIFont 宽度的字符串的前两行。 “get”是指得到一个子字符串。第二行可能会被截断,并且必须考虑到第一行的自动换行。

我怎样才能做到这一点?请告诉我正确的方向。谢谢!

【问题讨论】:

    标签: iphone objective-c ios ipad nsstring


    【解决方案1】:

    我认为没有一种简单、干净优雅的方法可以做到这一点。但是,如果您查看NSString UIKit Additions reference,有些方法可能有助于获得良好的近似值。

    具体看:

     CGSize aSize = 
     [ myString  sizeWithFont:(UIFont *)aFont 
            constrainedToSize:(CGSize ) aSize ];
    

    将 aSize 与您想要的宽度和 2*fontSize(2 行)用于您想要的高度。 取结果宽度(aSize.width)并除以您的字体大小。如果要放入此框,这应该近似于您的字符串将被截断的位置。

    现在不幸的是,您需要字体比例(点大小与宽度的比例),我不知道如何获得。我根据经验确定它在 4 到 6 之间,但这就像说 pi 大约是 3。

    无论如何,你的字符串被截断的近似索引将是

     ( fontRatio * aSize.width ) / fontSize;
    

    我编写了一个小型模拟器项目来测试线宽、字体比例、字体大小等的各种组合,欢迎您使用。在这里:string test project

    【讨论】:

    • 我玩了很多,似乎没有一个简单的解决方案。但是,这个答案给出了最好的近似值。谢谢!
    • @RafałSroka - NP。我很好奇为什么你需要知道这一点而不实际显示它。
    • 我正在显示它,但后来,我正在用它填充 UITableViewCells。我只是不想存储太多我不需要的数据。
    • 啊,过早的优化。为什么不直接从前面砍掉任意 500 个字符并使用它呢?除非您拥有数千个这样的数据,否则这不会是“太多数据”。
    • 我一开始就是这样做的,但那太容易了。我需要一个更好的近似值。
    【解决方案2】:

    这个怎么样?

    - (NSString*) stringWithString:(NSString*)longString width:(float)width font:(UIFont*)font {
    
        if([longString sizeWithFont:font].width < width) {
            return longString;
        }
    
        NSMutableString* mutString = [NSMutableString stringWithFormat:@""];
        int i = 0;
        while ([mutString sizeWithFont:font].width < width && i < [longString length]) {
            unichar ch = [longString characterAtIndex:i];
            [mutString appendString:[NSString stringWithCharacters:&ch length:1]];
            i++;
        }
    
        NSString* shortenedString = [mutString substringToIndex:[mutString length] - 1];
    
        return shortenedString;
    }
    

    基本上我一个一个地添加字符,每次都检查是否达到了所需的宽度。

    编辑:

    使用自动换行和两行代码,您可以调整上面的代码并使用以下内容检查大小:

    [mutString sizeWithFont:font constrainedToSize:CGSizeMake(9999999, font.lineHeight*2) lineBreakMode:UILineBreakModeWordWrap]
    

    除了单个字符,你也可以对单词做同样的事情:

    [longString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
    

    这将返回一个数组,其中包含字符串中可用于循环的所有单词。

    【讨论】:

    • 主要思想是好的,但这没有考虑自动换行。
    • 好的,所以你想要自动换行吗?最多两行?您是否关心各行的截断?
    • 是的,最后一行可以截断,必须考虑自动换行。我有数千个非常长的字符串,我不想存储,因为我只需要两个可以适应所需宽度的前行。
    【解决方案3】:

    您可以尝试将前两行文本放在具有必要宽度的UILabel 中。您可以设置此标签的字体。 然后你可以有另一个标签,它用不同的字体保存文本的剩余部分。 希望这会有所帮助。

    【讨论】:

    • 我不想使用 UILabel 来做这件事。我只需要我的字符串的一个子字符串。
    【解决方案4】:

    “get”是指绘制它,在前 2 行之后截断?或者检索一个字符串,该字符串表示前两行的空间适合什么?

    对于前者,你可以直接绘制它,UILabel 会为你截断。

    对于后者,我认为您将不得不自己打破这个词并测量子字符串以找出适合的内容。

    【讨论】:

    • “get”是指获取子字符串。
    【解决方案5】:
    const int kPadding = 4; // Padding for the diference between the font's height and the line height - it's 2 for front and 2 for bottom
    
    float maxHeight = (FONT_SIZE+kPadding)*kNumberOfLinesYouNeed;
    CGSize labelSize = [yourString sizeWithFont:yourFont constrainedToSize:CGSizeMake(kYourNeededWidth, maxHeight) lineBreakMode:UILineBreakModeWordWrap];
    youLabel.frame=CGRectMake(yourX, yourY, kYourNeededWidth, maxHeight);
    

    对于任何错误,我深表歉意。我已经在脑海中写下了这个表格。

    【讨论】:

    • 我只需要我的字符串的一个子字符串。我不想要具有所需高度的标签。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2010-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多