Можно ли использовать свойство autoshrink совместно с несколькими строками на UILabel
? например, возможен большой размер текста на 2 доступных строках.
Autoshrink на UILabel с несколькими линиями
Ответ 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];
}
Ответ 11
Я написал небольшую категорию в UILabel на основе ответа "The Dude" выше, чтобы достичь этой функциональности.
Ответ 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.