【问题标题】:NSString font size specific to frame width特定于框架宽度的 NSString 字体大小
【发布时间】:2013-02-11 18:09:04
【问题描述】:

我正在使用drawRect 进行文本显示,调用NSString。我正在尝试使用sizeWithFont 来实现自动调整字体大小(缩小),默认字体大小为 17,并使用循环将字体大小减小 1,如果它不适合宽度的大小。谁能帮助我如何实现这一点?现在的例子会很好,我只是将字体大小设置为 17.0

[[self.string displayName] drawAtPoint:CGPointMake(xcoord, ycoord) withFont:[UIFont boldSystemFontOfSize:17.0]];
CGSize size = [[self.patient displayName] sizeWithFont:[UIFont boldSystemFontOfSize:17.0]];
max_current_y = size.height > max_current_y ? size.height : max_current_y;
xcoord = xcoord + 3.0f + size.width;

【问题讨论】:

    标签: objective-c nsstring drawrect sizewithfont


    【解决方案1】:

    好吧,没关系。这是使用 NSString 为其返回字体的相同方法的修改版本:

        -(UIFont*)getFontForString:(NSString*)string
                   toFitInRect:(CGRect)rect
                      seedFont:(UIFont*)seedFont{
        UIFont* returnFont = seedFont;
        CGSize stringSize = [string sizeWithAttributes:@{NSFontAttributeName : seedFont}];
    
        while(stringSize.width > rect.size.width){
            returnFont = [UIFont systemFontOfSize:returnFont.pointSize -1];
            stringSize = [string sizeWithAttributes:@{NSFontAttributeName : returnFont}];
        }
    
        return returnFont;
    }
    

    这是如何称呼它的:

    NSString* stringToDraw = @"Test 123";
    
        CGRect rect = CGRectMake(100., 100., 100., 200.);
        UIFont* font = [self getFontForString:stringToDraw toFitInRect:rect seedFont:[UIFont systemFontOfSize:20]];
        [stringToDraw drawInRect:rect withFont:font];
    

    代码适用于 iOS7+

    【讨论】:

    • 我需要将 getFontForString 添加到类别吗?我究竟需要在哪里实施这些?
    • 您不必将此方法添加到类别中,因为我将其更改为采用 NSString。您可以在任何实用程序类中添加它,例如 StringHelper。 StringHelper 类可以是单例的。您获取共享的 StringHelper 对象,然后调用此方法。这有帮助吗?
    • 非常感谢它现在可以工作了!无法使用现有代码进行组装
    • 您好,只是一个改进:更改代码以调用种子字体大小的更改允许更通用的方法摆脱系统字体约束。更改:从 returnFont = [UIFont systemFontOfSize:returnFont.pointSize -1];returnFont = [returnFont fontWithSize:returnFont.pointSize -1];
    • 致命缺陷:你想要stringSize = [string sizeWithAttributes:@{NSFontAttributeName : returnFont}];(注意returnFont)否则你会陷入死循环。
    【解决方案2】:

    尝试使用 1.0 步的字体大小可能会非常慢。您可以通过对两种不同尺寸进行两种测量来极大地改进算法,然后使用线性近似来猜测与正确尺寸非常接近的尺寸。

    如果结果不够接近,请使用猜测的大小而不是前两个之一重复计算,直到它足够好或停止变化:

    // any values will do, prefer those near expected min and max
    CGFloat size1 = 12.0, size2 = 56.0; 
    CGFloat width1 = measure_for_size(size1);
    CGFloat width2 = measure_for_size(size2);
    
    while (1) {
        CGFloat guessed_size = size1 + (required_width - width1) * (size2 - size1) / (width2 - width1);
    
        width2 = measure_for_size(guessed_size);
        if ( fabs(guessed_size-size2) < some_epsilon || !is_close_enough(width2, required_width) ) {
            size2 = guessed_size;
            continue;
        }
        // round down to integer and clamp guessed_size as appropriate for your design
        return floor(clamp(guessed_size, 6.0, 24.0));
    }
    

    is_close_enough() 的实施完全取决于您。鉴于文本宽度几乎与字体大小呈线性增长,您可以简单地删除它并进行 2-4 次迭代就足够了。

    【讨论】:

    • 这是一个比对已接受答案的蛮力搜索更好的解决方案。值得注意的是,sizeWithFont: 自 iOS 7.0 起已弃用。替换调用 sizeWithAttributes: 是对此类搜索的显着改进,因为它返回精确的未舍入大小。
    【解决方案3】:

    我想尝试制作一个不必使用 do...while 循环反复检查字体大小的版本。相反,我假设字体点大小是线性比例,然后计算出所需框架宽度和实际框架宽度之间的大小差异,然后相应地调整字体大小。因此,我最终得到了这个功能:

    + (CGFloat)fontSizeToFitString:(NSString *)string inWidth:(float)width withFont:(UIFont *)font
    {
        UILabel *label = [UILabel new];
        label.font = font;
        label.text = string;
        [label sizeToFit];
    
        float ratio = width / label.frame.size.width;
        return font.pointSize * ratio;
    }
    

    传入任意大小的字体,以及字符串和所需的宽度,它会返回该字体的磅值。

    我还想更进一步,找出多行字符串的字体大小,以便最长的行在没有换行符的情况下适合:

    + (CGFloat)fontSizeToFitLongestLineOfString:(NSString *)string inWidth:(float)width withFont:(UIFont *)font
    {
        NSArray *stringLines = [string componentsSeparatedByString:@"\n"];
    
        UILabel *label = [UILabel new];
        label.font = font;
    
        float maxWidth = 0;
    
        for(NSString *line in stringLines)
        {
            label.text = line;
            [label sizeToFit];
            maxWidth = MAX(maxWidth, label.frame.size.width);
        }
    
        float ratio = width / maxWidth;
        return font.pointSize * ratio;
    }
    

    对我来说似乎工作得很好。希望对其他人有所帮助。

    【讨论】:

      【解决方案4】:

      原始海报没有说明他正在开发什么平台,但对于 Mavericks 上的 OSX 开发人员,sizeWithFont: 不存在,应该使用sizeWithAttributes

      NSSize newSize = [aString sizeWithAttributes:
      [NSDictionary dictionaryWithObjectsAndKeys:
                 [NSFont fontWithName:@"Arial Rounded MT Bold" size:53.0],NSFontAttributeName,nil
      ]];
      

      【讨论】:

        【解决方案5】:

        这是一种可以返回适合矩形的字体的方法:

        -(UIFont*)getFontToFitInRect:(CGRect)rect seedFont:(UIFont*)seedFont{
            UIFont* returnFont = seedFont;
            CGSize stringSize = [self sizeWithFont:returnFont];
        
            while(stringSize.width > rect.size.width){
                returnFont = [UIFont systemFontOfSize:returnFont.pointSize -1];
                stringSize = [self sizeWithFont:returnFont];
            }
        
            return returnFont;
        }
        

        您可以将此方法添加到 NSString 类别。您可以在此处找到有关如何添加类别的更多信息:http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html#//apple_ref/doc/uid/TP40011210-CH6-SW2

        如果您不想创建类别,可以将此方法添加到您的实用程序类之一,并传入您希望为其返回字体的字符串。

        【讨论】:

        • 您好,感谢您的帮助,但我无法理解添加类别。
        • 您能否提供一个示例,说明它的外观?谢谢
        • 我在下面留下了另一条评论。
        • 这是非常低效的。您可以只使用一个比率来计算所需的字体大小。无需循环。
        • 你是怎么做到的?对不起,我是新手
        【解决方案6】:

        这是另一种方法,受@puru020 和@jowie 答案的启发。希望它可以帮助某人

        -(UIFont *) adjustedFontSizeForString:(NSString *)string forWidth:(float)originalWidth forFont:(UIFont *)font
        {
            CGSize stringSize = [string sizeWithFont:font];
            if(stringSize.width <= originalWidth)
            {
                return font;
            }
            float ratio = originalWidth / stringSize.width;
            float fontSize = font.pointSize * ratio;
            return [font fontWithSize:fontSize];
        }
        

        【讨论】:

          【解决方案7】:

          我对@puru020的解决方案做了一点修改,增加了对属性的支持,又做了一点改进:

          注意:该方法应该被包裹在一个 NSString 类别中

          - (UIFont*)requiredFontToFitInSize:(CGSize)size seedFont:(UIFont*)seedFont attributes:(NSDictionary*)attributes{
             UIFont *returnFont = [UIFont systemFontOfSize:seedFont.pointSize +1];
             NSMutableDictionary *mutableAttributes = attributes.mutableCopy;
             CGSize stringSize;
          
             do {
              returnFont = [UIFont systemFontOfSize:returnFont.pointSize -1];
              [mutableAttributes setObject:returnFont forKey:NSFontAttributeName];
              stringSize = [self sizeWithAttributes:mutableAttributes];
             } while (stringSize.width > size.width);
          
             return returnFont;
          }
          

          【讨论】:

            猜你喜欢
            • 2020-06-09
            • 2017-06-10
            • 2011-05-03
            • 2011-07-23
            • 2013-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-22
            相关资源
            最近更新 更多