Autoshrink на UILabel с несколькими линиями

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

Ответ 1

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

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 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;"

Вся заслуга людей в 11pixel.

Ответ 2

Я несколько изменил приведенный выше код, чтобы сделать его категорией на 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

Ответ 3

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

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

  • Установите "Автозапуск" на "Минимальный размер шрифта".
  • Установите шрифт на свой самый большой желаемый размер шрифта (20) и установите Lines на, скажем, 10, что в моем случае было таким же много строк, которые соответствовали бы метке при этом размере шрифта.
  • Затем измените "Линия Breaks "от" Word Wrap "до" Truncate Tail. "

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

Ответ 4

Здесь решение категории обновлено до 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

Ответ 5

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

numberOfLines должен быть отличным от нуля

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

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

Ответ 6

Небольшая версия, адаптированная из @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

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

  • Установить ограничение ширины (чистая ширина или хвост и вывод)
  • УСТАНОВИТЕ ВЫСОТНУЮ КОНСТРУКЦИЮ (это очень важно, обычно с авторезистированием не устанавливается высота метки)
  • Устанавливает свойство "Autoshrink" как "Минимальная шкала шрифта" или "Минимальный размер шрифта" (работает в обоих случаях)
  • Задайте для свойства "Разрывы строк" ​​значение "Усечь хвост"
  • Задайте свойство "Lines" для ненулевого значения

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

Ответ 8

Мне понравился ответ 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

Ответ 9

Ответ itedcedor имеет проблему, о которой указал участник. Кроме того, нет необходимости обрезать пробелы. Здесь это измененная версия:

- (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];
}

Ответ 10

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

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

1 - Работа с iOS 6 (поскольку обе версии MinimumFontSize и 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];
}

Ответ 12

Для UIButton эти строки работают для меня:

self.centerBtn.titleLabel.numberOfLines = 2;
self.centerBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
self.centerBtn.titleLabel.adjustsFontSizeToFitWidth = YES;

Ответ 13

Существует метод NSString, -sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:, который, судя по всему, существует с iOS 2.0, но, к сожалению, он не рекомендуется в iOS 7 без предлагаемой альтернативы, так как автоматическое сокращение размера шрифта не рекомендуется. Я действительно не понимаю позицию Apple по этому поводу, так как они используют ее в ключевой записи и т.д., И я думаю, что если размеры шрифта находятся в пределах небольшого диапазона, все в порядке. Вот реализация в Swift с использованием этого метода.

var newFontSize: CGFloat = 30
    let font = UIFont.systemFontOfSize(newFontSize)
    (self.label.text as NSString).sizeWithFont(font, minFontSize: 20, actualFontSize: &newFontSize, forWidth: self.label.frame.size.width, lineBreakMode: NSLineBreakMode.ByWordWrapping)
    self.label.font = font.fontWithSize(newFontSize)

Я не знаю, как это можно добиться без использования устаревших методов.

Ответ 14

Я использовал решение @wbarksdale Swift 3, но обнаружил, что длинные слова усекаются посередине. Чтобы сохранить слова неповрежденными, мне пришлось изменить, как показано:

extension UILabel {
    func adjustFontSizeToFit(minimumFontSize: CGFloat, maximumFontSize: CGFloat? = nil) {
        let maxFontSize = maximumFontSize ?? font.pointSize
        let words = self.text?.components(separatedBy: " ")
        var longestWord: String?
        if let max = words?.max(by: {$1.characters.count > $0.characters.count}) {
            longestWord = max
        }
        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)

            let wordConstraintSize = CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT))
            let longestWordSize = ((longestWord ?? "") as NSString).boundingRect(with: wordConstraintSize,
                                                                    options: .usesFontLeading,
                                                                    attributes: [NSFontAttributeName: proposedFont],
                                                                    context: nil)

            if labelSize.height <= bounds.size.height && longestWordSize.width < constraintSize.width {
                font = proposedFont
                setNeedsLayout()
                break
            }
        }
    }
}

Ответ 15

Попробуйте следующее:

Любой подкласс UILabel или метод callFontSize call после установки свойства text на метке

override var text : String? { didSet { self.adjustFontSize() } }

func adjustFontSize()
{
    var lineCount = self.string.components(separatedBy: "\n").count - 1
    var textArray = self.string.components(separatedBy: " ")
    var wordsToCompare = 1
    while(textArray.count > 0)
    {
        let words = textArray.first(n: wordsToCompare).joined(separator: " ")
        let wordsWidth = words.widthForHeight(0, font: self.font)
        if(wordsWidth > self.frame.width)
        {
            textArray.removeFirst(wordsToCompare)
            lineCount += 1
            wordsToCompare = 1
        }
        else if(wordsToCompare > textArray.count)
        {
            break
        }
        else
        {
            wordsToCompare += 1
        }
    }
    self.numberOfLines = lineCount + 1
}

Ответ 16

extension UILabel{

func adjustFont(minSize:Int, maxSize:Int){
    var newFont = self.font
    for index in stride(from: maxSize, to: minSize, by: -1) {
        newFont = UIFont.systemFont(ofSize: CGFloat(index))
        let size = CGSize(width: self.frame.width, height: CGFloat(Int.max))
        let size2 = (self.text! as NSString).boundingRect(with: size, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedStringKey.font:newFont!], context: nil).size
        if size2.height < self.frame.size.height{
            break
        }
    }
    self.font = newFont
}

}

вам нужно присвоить значение свойству numberOfLines для UILabel.