Как настроить размер шрифта надписи под прямоугольник? - PullRequest
36 голосов
/ 16 мая 2010

Да, это классная myLabel.adjustsFontSizeToFitWidth = YES; собственность. Но как только у метки будет две или более строки, текст не будет изменен ни к чему. Так что он просто усекается с ... если он не вписывается в прямоугольник.

Есть ли другой способ сделать это?

Ответы [ 14 ]

0 голосов
/ 15 ноября 2016

Swift 3 «бинарное поисковое решение» на основе этого ответа с незначительными улучшениями. Образец в контексте UITextView подкласса:

func binarySearchOptimalFontSize(min: Int, max: Int) -> Int {
    let middleSize = (min + max) / 2

    if min > max {
        return middleSize
    }

    let middleFont = UIFont(name: font!.fontName, size: CGFloat(middleSize))!

    let attributes = [NSFontAttributeName : middleFont]
    let attributedString = NSAttributedString(string: text, attributes: attributes)

    let size = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
    let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
    let textSize = attributedString.boundingRect(with: size, options: options, context: nil)

    if textSize.size.equalTo(bounds.size) {
        return middleSize
    } else if (textSize.height > bounds.size.height || textSize.width > bounds.size.width) {
        return binarySearchOptimalFontSize(min: min, max: middleSize - 1)
    } else {
        return binarySearchOptimalFontSize(min: middleSize + 1, max: max)
    }
}

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 02 марта 2015

Все двоичные поиски хороши, но остановите рекурсию, используя проверки кадров, не так логично Лучше проверить размер шрифта, потому что UIFont поддерживает размер с плавающей точкой, и этот шрифт больше подходит Плюс использование стиля абзаца метки для точного вычисления размера.

Если кому-то интересно, можете посмотреть ниже код:

static UIFont * ___suitableFontInRangePrivate(const CGSize labelSize,
                                            NSParagraphStyle * paragraphStyle,
                                            NSString * fontName,
                                            NSString * text,
                                            const CGFloat minSize,
                                            const CGFloat maxSize)
{
    // Font size in range, middle size between max & min.
    const CGFloat currentSize = minSize + ((maxSize - minSize) / 2);

    // Font with middle size.
    UIFont * currentFont = [UIFont fontWithName:fontName size:currentSize];

    // Calculate text height.
    const CGFloat textHeight = [text boundingRectWithSize:CGSizeMake(labelSize.width, CGFLOAT_MAX)
                                                options:NSStringDrawingUsesLineFragmentOrigin
                                            attributes:@{ NSFontAttributeName : currentFont, NSParagraphStyleAttributeName : paragraphStyle }
                                                context:nil].size.height;
    CGFloat min, max;
    if (textHeight > labelSize.height)
    {
        // Take left range part.
        min = minSize;
        max = currentSize;
    }
    else
    {
        // Take right range part.
        min = currentSize;
        max = maxSize;
    }

    // If font size in int range [0.0; 2.0] - got it, othervice continue search.
    return ((max - min) <= 2.0) ? currentFont : ___suitableFontInRangePrivate(labelSize, paragraphStyle, fontName, text, min, max);
}

void UILabelAdjustsFontSizeToFrame(UILabel * label)
{
    if (!label) return;

    NSString * text = [label text];

    __block NSParagraphStyle * style = nil;
    [[label attributedText] enumerateAttributesInRange:NSMakeRange(0, [text length])
                                            options:(NSAttributedStringEnumerationOptions)0
                                            usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop){
                                                id paragraphStyle = [attrs objectForKey:@"NSParagraphStyle"];
                                                if (paragraphStyle) style = [paragraphStyle retain];
                                            }];

    if (!style)
    {
        NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
        if (!paragraphStyle) paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        if (paragraphStyle)
        {
            [paragraphStyle setLineBreakMode:[label lineBreakMode]];
            [paragraphStyle setAlignment:[label textAlignment]];
        }
        style = paragraphStyle;
    }

    UIFont * suitableFont = ___suitableFontInRangePrivate([label frame].size, style, [[label font] fontName], text, 0, 500);
    [label setFont:suitableFont];
    [style release];
}
0 голосов
/ 16 августа 2014

Я создал категорию для UILabel на основе ответа @ agarcian. Но я рассчитываю fontSize в зависимости от площади, необходимой на экране для рисования текста. Этот метод не требует циклов и вычисление выполняется за одну итерацию.

Здесь файл .h:

//  UILabel+Extended.h
//  Created by Firuz on 16/08/14.
//  Copyright (c) 2014. All rights reserved.

#import <UIKit/UIKit.h>

@interface UILabel (Extended)

/** This method calculate the optimal font size for current number of lines in UILable. Mus be called after drawing UILabel view */
- (NSInteger)fontSizeWithMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize;

@end

А вот файл .m:

//  UILabel+Extended.m
//  Created by Firuz on 16/08/14.
//  Copyright (c) 2014. All rights reserved.

#import "UILabel+Extended.h"

@implementation UILabel (Extended)

- (NSInteger)fontSizeWithMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize
{
    if (maxFontSize < minFontSize) {
        return 0;
    }

    UIFont *font = [UIFont fontWithName:self.font.fontName size:maxFontSize];

    CGFloat lineHeight = [font lineHeight];

    CGSize constraintSize = CGSizeMake(MAXFLOAT, lineHeight);

    CGRect rect = [self.text boundingRectWithSize:constraintSize
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                        attributes:@{NSFontAttributeName : font}
                                           context:nil];

    CGFloat labelSqr = self.frame.size.width * self.frame.size.height;
    CGFloat stringSqr = rect.size.width/self.frame.size.width * (lineHeight + font.pointSize) * self.frame.size.width;

    CGFloat multiplyer = labelSqr/stringSqr;

    if (multiplyer < 1) {
        if (minFontSize < maxFontSize*multiplyer) {
            return maxFontSize * multiplyer;
        } else {
            return minFontSize;
        }
    }
    return maxFontSize;
}

@end
0 голосов
/ 14 июня 2013

Поиск работы по замку Нильса.

Вот та же идея с другой реализацией.
Мое решение более точное, но при этом требует гораздо больше ресурсов процессора.

Добавьте эту функцию в класс, который наследует UILabel.

-(void)fitCurrentFrame{

    CGSize iHave = self.frame.size;

    BOOL isContained = NO;
    do{
        CGSize iWant = [self.text sizeWithFont:self.font];
        if(iWant.width > iHave.width || iWant.height > iHave.height){
            self.font = [UIFont fontWithName:self.font.fontName size:self.font.pointSize - 0.1];
            isContained = NO;
        }else{
            isContained = YES;
        }

    }while (isContained == NO);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...