【问题标题】:CTFrameGetVisibleStringRange equivalent for iOS programming?CTFrameGetVisibleStringRange 等效于 iOS 编程?
【发布时间】:2011-03-20 06:06:51
【问题描述】:

我需要一个像 CTFrameGetVisibleStringRange 这样的方法,它可以为我提供将以换行模式(即自动换行)提供的给定大小呈现的文本。例如,我有很长的一行文本.. 并且我有一个给定的矩形来绘制包含在其中的文本,但是无论文本被截断,我都会继续在它停止的另一个区域呈现它。所以我需要一个类似的方法:

NSString * text = "The lazy fox jumped over the creek";
[text drawAtPoint:CGPointMake(0, 0) forWidth:20 withFont:[UIFont fontWithName:@"Arial" size:10] lineBreakMode:UILineBreakModeWordWrap];
// now I do I know how much it drew before it stopped rendering?

有人有什么想法吗?

**已编辑:请参阅我的解决方案。

【问题讨论】:

    标签: iphone sizewithfont


    【解决方案1】:

    我遇到了类似的问题,我使用了 Mike 发布的解决方案。

    然而,事实证明,trimToWord 经常给我一些太多的单词,超出了我指定的 UILabel 大小。我发现如果我将 while 循环运算符更改为 >= 而不仅仅是 >,它可以完美运行。

    我还添加了一些 ivars(chopIndexremainingBody),用于获取剩余的字符串,以便在下一个 UILabel 中显示。

    这是我使用的解决方案。

    -(NSString*) rewindOneWord:(NSString*) str{
        // rewind by one word
        NSRange lastspace = [str rangeOfString:@" " options:NSBackwardsSearch];
        if (lastspace.location != NSNotFound){
            int amount = [str length]-lastspace.location;
            chopIndex -= amount;
            return [str substringToIndex:lastspace.location];
        }else {
            // no spaces, lets just rewind 2 characters at a time
            chopIndex -= 2;
            return [str substringToIndex:[str length]-2];
        }
    }
    
    // returns only how much text it could render with the given stipulations   
    -(NSString*) trimToWord:(NSString*)str sizeConstraints:(CGSize)availableSize withFont:(UIFont*)font{
        if(str == @"")
            return str;
    
        CGSize measured = [str sizeWithFont:font constrainedToSize:CGSizeMake(availableSize.width, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];
        // 'guess' how much we will need to cut to save on processing time
        float choppedPercent = (((double)availableSize.height)/((double)measured.height));
        if(choppedPercent >= 1.0){
            //entire string can fit in availableSize
            remainingBody = @"";
            return str;
        }
    
        chopIndex = choppedPercent*((double)[str length]);
        str = [str substringToIndex:chopIndex];
        // rewind to the beginning of the word in case we are in the middle of one
        do{
            str = [self rewindOneWord:str];
            measured = [str sizeWithFont:font constrainedToSize:availableSize lineBreakMode:UILineBreakModeWordWrap];
        }while(measured.height>=availableSize.height);
    
        //increment past the last space in the chopIndex
        chopIndex++;
    
        //update the remaining string
        remainingBody = [remainingBody substringFromIndex:chopIndex];
    
        return str;
    }
    

    【讨论】:

    • 在您改进了我的解决方案后,我已将这个问题的答案授予您。谢谢@teradyl
    【解决方案2】:

    这里有一个解决方案。它相当快。它“猜测”首先在哪里切,然后逐字回滚。 sizewithFont 调用相当昂贵,因此这个初始“猜测”步骤很重要。主要方法是trimToWord:sizeConstraints:withFont。

    请随意评论我如何改进这一点。

    -(NSString*) rewindOneWord:(NSString*) str{
        // rewind by one word
        NSRange lastspace = [str rangeOfString:@" " options:NSBackwardsSearch];
        if (lastspace.location != NSNotFound){
            int amount = [str length]-lastspace.location;
            return [str substringToIndex:lastspace.location];
        }else {
            // no spaces, lets just rewind 2 characters at a time
            return [str substringToIndex:[str length]-2];
        }
    }
    
    // returns only how much text it could render with the given stipulations   
    -(NSString*) trimToWord:(NSString*) str sizeConstraints:(CGSize) avail withFont:(UIFont*) font{
        CGSize measured = [str sizeWithFont:font constrainedToSize:CGSizeMake(avail.width, 1000000) lineBreakMode:UILineBreakModeWordWrap];
        // 'guess' how much we will need to cut to save on processing time
        float choppedPercent = (((double)avail.height)/((double)measured.height));
        if (choppedPercent >= 1.0){
            return str;
        }
    
        int chopIndex = choppedPercent*((double)[str length]);
        str = [str substringToIndex:chopIndex];
        // rewind to the beginning of the word in case we are in the middle of one
        str = [self rewindOneWord:str];
        measured = [str sizeWithFont:font constrainedToSize:avail lineBreakMode:UILineBreakModeWordWrap];
        while (measured.height>avail.height){
            str = [self rewindOneWord:str];
            measured = [str sizeWithFont:font constrainedToSize:avail lineBreakMode:UILineBreakModeWordWrap];
        }
        return str;
    }
    

    【讨论】:

      【解决方案3】:

      我不认为CTFrameGetVisibleStringRange有替代品,虽然我们可以用下面的方法得到同样的结果。

      - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
      

      苹果文档

      http://developer.apple.com/library/ios/#documentation/uikit/reference/NSString_UIKit_Additions/Reference/Reference.html

      已编辑:以下代码显示了我的方法

      NSString * text = "The lazy fox jumped over the creek";
      
      NSArray* m_Array = [text  componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@" "]];
      
      CGSize mySize = CGSizeMake(300,180);
      NSMutableString* myString = [[NSMutableString alloc] initWithString:@""];
      
      //The below code till the end of the while statement could be put in separate function.
      
      CGSize tempSize = CGSizeMake(0,0);
      NSInteger index = 0 ;
      do
      {
            [myString  appendString:[m_Array objectAtIndex:index]];
            tempSize  = [myString  sizeWithFont:myfont constrainedToSize: 
            CGSizeMake(mySize.width, CGFLOAT_MAX) lineBreakMode: UILineBreakModeWordWrap];
            index++;
      
      }while(tempSize.height < mySize.height && index <= [m_Array count])
      
      //Remove the string items from m_Array till the (index-1) index,
      
      [self RemoveItems:m_Array tillIndex:(index-1)];//Plz define you own
      
      //you have the myString which could be fitted in CGSizeMake(300,180);
      
      
      //Now start with remaining Array items with the same way as we have done above.
      }
      

      【讨论】:

      • 这给了我一个大小。我需要知道字符串的哪一部分被绘制了。
      • @Mike Simmons:是的,通过使用此功能,您可以检查最少的单词组来填充给定的矩形。
      • 我喜欢您采用该解决方案的方向,但 myString 最终没有空格。此外,即使您追加空格字符,它也不允许单词之间有 2 个空格字符的情况。我需要我的字符串完美地代表它之前的样子。
      • 对于每个单词一遍又一遍地调用 sizeWitFont 也很慢,这就是为什么我希望在 iOS 框架中有某种 CTFrameGetVisibleStringRange 等价物。就目前而言,我可以看到您的代码的唯一解决方案是逐个字符地遍历,这可能会再次慢 5 倍。
      • 我忘记在 [split objectAtIndex:index]] 之后添加空格字符;
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      • 2013-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      相关资源
      最近更新 更多