Автоусадка на UILabel с несколькими строками - PullRequest
54 голосов
/ 30 января 2012

Возможно ли использовать свойство автоусадки совместно для нескольких строк в UILabel? например, большой размер текста возможен в 2 доступных строках.

Ответы [ 16 ]

46 голосов
/ 27 июля 2012

Я несколько изменил приведенный выше код, чтобы сделать его категорией для UILabel:

Заголовочный файл:

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

И файл реализации:

@implementation UILabel (MultiLineAutoSize)

- (void)adjustFontSizeToFit
{
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumFontSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}

@end
39 голосов
/ 30 января 2012

Эти люди нашли решение:

http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/

Их решение заключается в следующем:

int maxDesiredFontSize = 28;
int minFontSize = 10;
CGFloat labelWidth = 260.0f;
CGFloat labelRequiredHeight = 180.0f;
//Create a string with the text we want to display.
self.ourText = @"This is your variable-length string. Assign it any way you want!";

/* This is where we define the ideal font that the Label wants to use.
   Use the font you want to use and the largest font size you want to use. */
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize];

int i;
/* Time to calculate the needed font size.
   This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
   Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = maxDesiredFontSize; i > minFontSize; i=i-2)
{
    // Set the new font size.
    font = [font fontWithSize:i];
    // You can log the size you're trying: NSLog(@"Trying size: %u", i);

    /* This step is important: We make a constraint box 
       using only the fixed WIDTH of the UILabel. The height will
       be checked later. */ 
    CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT);

    // This step checks how tall the label would be with the desired font.
    CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

    /* Here is where you use the height requirement!
       Set the value in the if statement to the height of your UILabel
       If the label fits into your required height, it will break the loop
       and use that font size. */
    if(labelSize.height <= labelRequiredHeight)
        break;
}
// You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i);

// Set the UILabel's font to the newly adjusted font.
msg.font = font;

// Put the text into the UILabel outlet variable.
msg.text = self.ourText;

Чтобы это работало, IBOutlet должен быть назначен в конструкторе интерфейсов для UILabel.

"IBOutlet UILabel * msg;"

Вся заслуга людей на 11 пикселей.

38 голосов
/ 02 июля 2015

Я нашел эту ссылку http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/

Проблема может быть решена с помощью Interface Builder в 3 простых шага:

  1. Установите для параметра «Автоусадка» значение «Минимальный размер шрифта».
  2. Установите шрифт на ваш Наибольший желаемый размер шрифта (20) и установить линии, скажем, 10, который в моем случае был как много строк, которые поместились бы в метке при таком размере шрифта
  3. Затем измените «Строка Перерывы »от« Перенос слов »до« Обрезать хвост ».

Надеюсь, это поможет!

24 голосов
/ 11 декабря 2013

Вот решение категории, обновленное до iOS 7 на основе обновлений itecedor для iOS 6.

Заголовочный файл:

#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
    - (void)adjustFontSizeToFit;
@end

И файл реализации:

@implementation UILabel (MultiLineAutoSize)


- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);

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

        CGSize labelSize = textRect.size;


        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout]; }


@end
11 голосов
/ 27 апреля 2015

Ответ, помеченный как решение, является хакерским и неточным.UILabel будет обрабатывать его автоматически, если вы правильно установите следующие свойства:

numberOfLines должно быть ненулевым

adjustsFontSizeToFitWidth должно быть YES

lineBreakMode должно не быть NSLineBreakByCharWrapping или NSLineBreakByWordWrapping

8 голосов
/ 19 марта 2015

Быстрая версия, адаптированная от @DaGaMs.

SWIFT 2:

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) {
            let proposedFont = font.fontWithSize(size)
            let constraintSize = CGSizeMake(bounds.size.width, CGFloat(MAXFLOAT))
            let labelSize = ((text ?? "") as NSString).boundingRectWithSize(constraintSize,
                options: .UsesLineFragmentOrigin,
                attributes: [NSFontAttributeName: proposedFont],
                context: nil)
            if labelSize.height <= bounds.size.height {
                font = proposedFont
                setNeedsLayout()
                break;
            }
        }
    }
}

SWIFT 3:

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        for size in stride(from: maxFontSize, to: minimumFontSize, by: -CGFloat(0.1)) {
            let proposedFont = font.withSize(size)
            let constraintSize = CGSize(width: bounds.size.width, height: CGFloat(MAXFLOAT))
            let labelSize = ((text ?? "") as NSString).boundingRect(with: constraintSize,
                                                                            options: .usesLineFragmentOrigin,
                                                                            attributes: [NSFontAttributeName: proposedFont],
                                                                            context: nil)
            if labelSize.height <= bounds.size.height {
                font = proposedFont
                setNeedsLayout()
                break;
            }
        }
    }
}
7 голосов
/ 21 июля 2016

Я не могу комментировать пост MontiRabbit из-за отсутствия репутации, поэтому я сделаю новый ответ.Решение, которое он (и ее реферер) предложил, не работает на Xcode 7.3 или лучше, оно неточное.Чтобы это работало, в раскадровке мне нужно было:

  1. Установить ограничение ширины (чистая ширина или хвост и поводок)
  2. Установить ограничение высоты (это очень важно, обычно с авторазмеромне устанавливается высота надписи)
  3. Установите для свойства "Автоусадка" значение "Минимальный масштаб шрифта" или "Минимальный размер шрифта" (работает в обоих случаях)
  4. Установите для свойства "Разрыв строки""Усеченный хвост"
  5. Установить для свойства "Линии" ненулевое значение

Надеюсь, это поможет!;)

6 голосов
/ 18 марта 2013

В ответе itedcedor есть проблема, на которую указал pwightman.Кроме того, нет необходимости обрезать пробелы.Вот это модифицированная версия:

- (void)adjustFontSizeToFit {
    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor * self.font.pointSize; maxSize -= 1.f) {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];

        if(labelSize.height <= size.height) {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }

    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}
6 голосов
/ 03 августа 2012

Мне понравился ответ DaGaMs, но при использовании меток, как в UITableViewCells, которые могут быть возвращены из dequeueReusableCell:, обычный размер шрифта продолжал бы уменьшаться, даже если исходный размер шрифта все еще был желателен для некоторых ячеек tableView, которые имели меньше текста и могли использовать оригинальный размер шрифта оригинальной этикетки.

Итак, я начал с категории DaGaMs в качестве отправной точки, я создал отдельный класс, а не отдельную категорию, и я убедился, что мои UILabels в моей раскадровке используют этот новый класс:

#import "MultiLineAutoShrinkLabel.h"

@interface MultiLineAutoShrinkLabel ()
@property (readonly, nonatomic) UIFont* originalFont;
@end

@implementation MultiLineAutoShrinkLabel

@synthesize originalFont = _originalFont;

- (UIFont*)originalFont { return _originalFont ? _originalFont : (_originalFont = self.font); }

- (void)quoteAutoshrinkUnquote
{
    UIFont* font = self.originalFont;
    CGSize frameSize = self.frame.size;

    CGFloat testFontSize = _originalFont.pointSize;
    for (; testFontSize >= self.minimumFontSize; testFontSize -= 0.5)
    {
        CGSize constraintSize = CGSizeMake(frameSize.width, MAXFLOAT);
        CGSize testFrameSize = [self.text sizeWithFont:(font = [font fontWithSize:testFontSize])
                                     constrainedToSize:constraintSize
                                         lineBreakMode:self.lineBreakMode];
        // the ratio of testFontSize to original font-size sort of accounts for number of lines
        if (testFrameSize.height <= frameSize.height * (testFontSize/_originalFont.pointSize))
            break;
    }

    self.font = font;
    [self setNeedsLayout];
}

@end
4 голосов
/ 15 февраля 2013

Спасибо DaGaMs за это решение.

Я обновил его следующим образом:

1 - для работы с iOS 6 (так как и minimalFontSize, и UILineBreakModeWordWrap устарели) 2 - убрать пробелы из текста метки, так как это приведет к сбою изменения размера (вы не хотите знать, сколько времени мне понадобилось, чтобы найти эту ошибку)

-(void)adjustFontSizeToFit 
{
    self.text = [self.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    UIFont *font = self.font;
    CGSize size = self.frame.size;

    for (CGFloat maxSize = self.font.pointSize; maxSize >= self.minimumScaleFactor; maxSize -= 1.f)
    {
        font = [font fontWithSize:maxSize];
        CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
        CGSize labelSize = [self.text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
        if(labelSize.height <= size.height)
        {
            self.font = font;
            [self setNeedsLayout];
            break;
        }
    }
    // set the font to the minimum size anyway
    self.font = font;
    [self setNeedsLayout];
}
...