是的,有這個很酷的myLabel.adjustsFontSizeToFitWidth = YES;
屬性。但只要標籤有兩行或更多行,它就不會將文本重新調整爲任何東西。所以它會被截斷...如果它不適合rect。如何調整標籤的字體大小以適應矩形?
有沒有另一種方法呢?
是的,有這個很酷的myLabel.adjustsFontSizeToFitWidth = YES;
屬性。但只要標籤有兩行或更多行,它就不會將文本重新調整爲任何東西。所以它會被截斷...如果它不適合rect。如何調整標籤的字體大小以適應矩形?
有沒有另一種方法呢?
如果你想確保標籤在寬度和高度方面都符合矩形,你可以在標籤上嘗試不同的字體大小,看看是否適合。
該片段始於300 pt,並嘗試通過減小字體大小來使標籤適合目標矩形。
- (void) sizeLabel: (UILabel *) label toRect: (CGRect) labelRect {
// Set the frame of the label to the targeted rectangle
label.frame = labelRect;
// Try all font sizes from largest to smallest font size
int fontSize = 300;
int minFontSize = 5;
// Fit label width wize
CGSize constraintSize = CGSizeMake(label.frame.size.width, MAXFLOAT);
do {
// Set current font size
label.font = [UIFont fontWithName:label.font.fontName size:fontSize];
// Find label size for current font size
CGRect textRect = [[label text] boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName: label.font}
context:nil];
CGSize labelSize = textRect.size;
// Done, if created label is within target size
if(labelSize.height <= label.frame.size.height)
break;
// Decrease the font size and try again
fontSize -= 2;
} while (fontSize > minFontSize);
}
還設置myLabel.numberOfLines = 10
或無論您想要的最大數量的行。
或者乾脆0線 – 2011-09-21 15:47:28
^這傢伙知道他在談論 – GangstaGraham 2013-08-26 10:29:20
我發現尼爾斯的答案是這個問題的最佳答案。不過,我有一個UIView,可以有100個標籤,我需要適合文本,所以這個過程效率很低,我可以感受到性能上的衝擊。
這是他的代碼修改爲使用二進制搜索,而不是線性搜索。現在它工作非常有效。
- (NSInteger)binarySearchForFontSizeForLabel:(UILabel *)label withMinFontSize:(NSInteger)minFontSize withMaxFontSize:(NSInteger)maxFontSize withSize:(CGSize)size {
// If the sizes are incorrect, return 0, or error, or an assertion.
if (maxFontSize < minFontSize) {
return 0;
}
// Find the middle
NSInteger fontSize = (minFontSize + maxFontSize)/2;
// Create the font
UIFont *font = [UIFont fontWithName:label.font.fontName size:fontSize];
// Create a constraint size with max height
CGSize constraintSize = CGSizeMake(size.width, MAXFLOAT);
// Find label size for current font size
CGRect rect = [label.text boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName : font}
context:nil];
CGSize labelSize = rect.size;
// EDIT: The next block is modified from the original answer posted in SO to consider the width in the decision. This works much better for certain labels that are too thin and were giving bad results.
if (labelSize.height >= (size.height + 10) && labelSize.width >= (size.width + 10) && labelSize.height <= (size.height) && labelSize.width <= (size.width)) {
return fontSize;
} else if (labelSize.height > size.height || labelSize.width > size.width) {
return [self binarySearchForFontSizeForLabel:label withMinFontSize:minFontSize withMaxFontSize:fontSize - 1 withSize:size];
} else {
return [self binarySearchForFontSizeForLabel:label withMinFontSize:fontSize + 1 withMaxFontSize:maxFontSize withSize:size];
}
}
- (void)sizeBinaryLabel:(UILabel *)label toRect:(CGRect)labelRect {
// Set the frame of the label to the targeted rectangle
label.frame = labelRect;
// Try all font sizes from largest to smallest font
int maxFontSize = 300;
int minFontSize = 5;
NSInteger size = [self binarySearchForFontSizeForLabel:label withMinFontSize:minFontSize withMaxFontSize:maxFontSize withSize:label.frame.size];
label.font = [UIFont fontWithName:label.font.fontName size:size];
}
尼爾斯城代碼工作的發現。
下面是使用不同實現的相同想法。
我的解決方案更精確,但也要佔用更多的CPU資源。
將此函數添加到繼承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);
}
如果有人正在尋找的MonoTouch/Xamarin.iOS實現,像我一樣......在這裏你去:
private int BinarySearchForFontSizeForText(NSString text, int minFontSize, int maxFontSize, SizeF size)
{
if (maxFontSize < minFontSize)
return minFontSize;
int fontSize = (minFontSize + maxFontSize)/2;
UIFont font = UIFont.BoldSystemFontOfSize(fontSize);
var constraintSize = new SizeF(size.Width, float.MaxValue);
SizeF labelSize = text.StringSize(font, constraintSize, UILineBreakMode.WordWrap);
if (labelSize.Height >= size.Height + 10 && labelSize.Width >= size.Width + 10 && labelSize.Height <= size.Height && labelSize.Width <= size.Width)
return fontSize;
else if (labelSize.Height > size.Height || labelSize.Width > size.Width)
return BinarySearchForFontSizeForText(text, minFontSize, fontSize - 1, size);
else
return BinarySearchForFontSizeForText(text, fontSize + 1, maxFontSize, size);
}
private void SizeLabelToRect(UILabel label, RectangleF labelRect)
{
label.Frame = labelRect;
int maxFontSize = 300;
int minFontSize = 5;
int size = BinarySearchForFontSizeForText(new NSString(label.Text), minFontSize, maxFontSize, label.Frame.Size);
label.Font = UIFont.SystemFontOfSize(size);
}
它的agarcian的距離的Objective-C到C#代碼的轉換,稍作修改:由於返回結果始終爲0(see the comment of borked)我正在返回計算的minFontSize,這會導致正確的字體大小。
非常感謝您的「小修改」。 – 2014-04-30 12:52:09
我已根據@ agarcian的回答爲UILabel創建了類別。但我計算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
所有二進制搜索都是不錯的,但使用幀檢查沒有那麼邏輯上停止遞歸。更好地檢查字體大小,導致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];
}
下面是根據@NielsCastle答案斯威夫特版,採用二進制搜索
extension UILabel{
func adjustFontSizeToFitRect(rect : CGRect){
if text == nil{
return
}
frame = rect
let maxFontSize: CGFloat = 100.0
let minFontSize: CGFloat = 5.0
var q = Int(maxFontSize)
var p = Int(minFontSize)
let constraintSize = CGSize(width: rect.width, height: CGFloat.max)
while(p <= q){
let currentSize = (p + q)/2
font = font.fontWithSize(CGFloat(currentSize))
let text = NSAttributedString(string: self.text!, attributes: [NSFontAttributeName:font])
let textRect = text.boundingRectWithSize(constraintSize, options: .UsesLineFragmentOrigin, context: nil)
let labelSize = textRect.size
if labelSize.height < frame.height && labelSize.height >= frame.height-10 && labelSize.width < frame.width && labelSize.width >= frame.width-10 {
break
}else if labelSize.height > frame.height || labelSize.width > frame.width{
q = currentSize - 1
}else{
p = currentSize + 1
}
}
}
}
使用
label.adjustFontSizeToFitRect(rect)
經常只是
label.adjustFontSizeToFitRect(rect.frame)
不錯,謝謝:) - 我只會建議使用[guard statement](https://www.hackingwithswift.com/new-syntax-swift-2-guard)取代這個早期回報。 – Mikolaj 2016-05-30 17:19:57
@nRewik沒有工作... – 2016-08-01 01:14:34
@nRewik工作很好。只有部分,這是越野車是當你使'UILabel'相當高的高度,然後字體大小計算亂七八糟,它超出了寬度。將嘗試解決這個錯誤,並在這裏發佈。 – 2016-09-13 07:24:54
該解決方案(基於this answer)的作品,支持自動佈局和執行二進制搜索找到最好的字體大小。
我發現唯一的警告是你不能指定行數(因爲AFAIK你不能告訴boundingRectWithSize
你想要多少行)。
AdjustableLabel.h
#import <UIKit/UIKit.h>
@interface AdjustableLabel : UILabel
/**
If set to YES, font size will be automatically adjusted to frame.
Note: numberOfLines can't be specified so it will be set to 0.
*/
@property(nonatomic) BOOL adjustsFontSizeToFitFrame;
@end
AdjustableLabel.m
#import "AdjustableLabel.h"
@interface AdjustableLabel()
@property(nonatomic) BOOL fontSizeAdjusted;
@end
// The size found S satisfies: S fits in the frame and and S+DELTA doesn't.
#define DELTA 0.5
@implementation AdjustableLabel
- (void)setAdjustsFontSizeToFitFrame:(BOOL)adjustsFontSizeToFitFrame
{
_adjustsFontSizeToFitFrame = adjustsFontSizeToFitFrame;
if (adjustsFontSizeToFitFrame) {
self.numberOfLines = 0; // because boundingRectWithSize works like this was 0 anyway
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.adjustsFontSizeToFitFrame && !self.fontSizeAdjusted)
{
self.fontSizeAdjusted = YES; // to avoid recursion, because adjustFontSizeToFrame will trigger this method again
[self adjustFontSizeToFrame];
}
}
- (void) adjustFontSizeToFrame
{
UILabel* label = self;
if (label.text.length == 0) return;
// Necessary or single-char texts won't be correctly adjusted
BOOL checkWidth = label.text.length == 1;
CGSize labelSize = label.frame.size;
// Fit label width-wise
CGSize constraintSize = CGSizeMake(checkWidth ? MAXFLOAT : labelSize.width, MAXFLOAT);
// Try all font sizes from largest to smallest font size
CGFloat maxFontSize = 300;
CGFloat minFontSize = 5;
NSString* text = label.text;
UIFont* font = label.font;
while (true)
{
// Binary search between min and max
CGFloat fontSize = (maxFontSize + minFontSize)/2;
// Exit if approached minFontSize enough
if (fontSize - minFontSize < DELTA/2) {
font = [UIFont fontWithName:font.fontName size:minFontSize];
break; // Exit because we reached the biggest font size that fits
} else {
font = [UIFont fontWithName:font.fontName size:fontSize];
}
// Find label size for current font size
CGRect rect = [text boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName : font}
context:nil];
// Now we discard a half
if(rect.size.height <= labelSize.height && (!checkWidth || rect.size.width <= labelSize.width)) {
minFontSize = fontSize; // the best size is in the bigger half
} else {
maxFontSize = fontSize; // the best size is in the smaller half
}
}
label.font = font;
}
@end
使用
AdjustableLabel* label = [[AdjustableLabel alloc] init];
label.adjustsFontSizeToFitFrame = YES;
// In case you change the font, the size you set doesn't matter
label.font = [UIFont fontWithName:@"OpenSans-Light" size:20];
這。作品。完美。 – Fattie 2016-05-17 03:02:53
這非常優雅,而且效果很好。我有一個小小的改進,它允許標籤文本是單個單詞的情況。在這種情況下,你不希望它跨行分割,所以我補充說: '//如果只有一個單詞,那麼請降低高度,以便強制boundingRectWithSize適合它'//一個line.' ''//' 如果([label.text componentsSeparatedByString:@」「] .Count之間== 1){'' labelSize.height/= 2.0;'' }'剛過 聲明labelSize。 – PKCLsoft 2017-11-02 11:33:43
這裏有一個斯威夫特內線UILabel的外掛。它運行一個二進制搜索算法來調整標籤的字體和界限,並進行測試,以針對iOS 9.
USAGE工作:字體大小調整以適合尺寸的100×100(1.0字體點內準確)。
<label>.fitFontForSize(CGSizeMake(100.0, 100.0))
複製/粘貼以下到您的文件
extension UILabel {
func fitFontForSize(constrainedSize : CGSize, var maxFontSize : CGFloat = 300.0, var minFontSize : CGFloat = 5.0, accuracy : CGFloat = 1.0) {
assert(maxFontSize > minFontSize)
while maxFontSize - minFontSize > accuracy {
let midFontSize : CGFloat = ((minFontSize + maxFontSize)/2)
font = font.fontWithSize(midFontSize)
sizeToFit()
let checkSize : CGSize = bounds.size
if checkSize.height < constrainedSize.height && checkSize.width < constrainedSize.width {
minFontSize = midFontSize
} else {
maxFontSize = midFontSize
}
}
font = font.fontWithSize(minFontSize)
sizeToFit()
}
}
注: 標籤的寬度和高度的限制不應會爲了這個工作組。一個簡單的解決方法是將標籤嵌入到具有設置大小限制的UIView中,然後調用上面定義的函數(如下所示)。
<label>.fitFontForSize(<superview>.bounds.size)
不錯的擴展;)請記住函數聲明中的'var'參數實際上已被棄用,並將在Swift 3中刪除。 – rafalkitta 2016-05-24 14:50:41
所有這些,都是對原來的問題有趣的解決方案,但是所有的人都還缺少一個重要的事情:如果你僅僅依靠familyName得到下一個字體進行測試,你失去的權重信息和可能更高級的屬性,像小帽子,人物風格等
更好的辦法是,而不是通過周圍的字體名稱和做[UIFont fontWithName:someFontName size:someFontSize]
,傳遞UIFontDescriptor
對象一起,然後做 [UIFont fontWithDescriptor:someFontDescriptor size:someFontSize]
。
因爲我沒有找到工作解決方案使用上述答案回答我所有的需求,我創建了我自己的組件提供以下功能:使用時FittableFontLabel
NSAttributedStrings
支持以及基本的字符串如果你們中的任何有趣的是,它的使用 的CocoaPods全迅速可用庫:https://github.com/tbaranes/FittableFontLabel
斯威夫特3「二進制搜索解決方案」的基礎上this與答案小的改進。樣本是在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)
}
}
我希望能幫助別人。
這不起作用。將'greatestFiniteMagnitude'交換爲寬度,如'CGSize(width:bounds.width,height:.greatestFiniteMagnitude)' – zrubenst 2017-07-01 21:15:07
@ agarcian的回答很接近,但它並沒有完全爲我工作,因爲有人在評論別人提到的,它總是返回0。
這裏是我的嘗試。
乾杯!
/**
* Returns the font size required in order to fit the specified text in the specified area.
* NB! When drawing, be sure to pass in the same options that we pass to boundingRectWithSize:options:attributes:context:
* Heavily modified form of: http://stackoverflow.com/a/14662750/1027452
*/
+(NSInteger)fontSizeForText:(NSString *)text withFont:(UIFont *)font inArea:(CGSize)areaSize minFontSize:(NSInteger)minFontSize maxFontSize:(NSInteger)maxFontSize
{
// If the sizes are incorrect, return 0, or error, or an assertion.
if (maxFontSize < minFontSize) {
return 0;
}
// Find the middle
NSInteger fontSize = (minFontSize + maxFontSize)/2;
// Create the font
UIFont *f = [UIFont fontWithName:font.fontName size:fontSize];
// Create a constraint size with max height
CGSize constraintSize = CGSizeMake(areaSize.width, MAXFLOAT);
// Find label size for current font size
CGRect rect = [text boundingRectWithSize:constraintSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:@{NSFontAttributeName : f}
context:nil];
CGSize labelSize = rect.size;
if (labelSize.height <= areaSize.height && labelSize.width <= areaSize.width)
{
return fontSize;
}
else if (labelSize.height > areaSize.height || labelSize.width > areaSize.width)
{
return [self fontSizeForText:text withFont:f inArea:areaSize minFontSize:minFontSize maxFontSize:maxFontSize -1];;
}
else
{
return [self fontSizeForText:text withFont:f inArea:areaSize minFontSize:minFontSize+1 maxFontSize:maxFontSize];;
}
}
尋找幾個小時後的無限數量,這一直是隻爲我工作的解決方案。我只是想知道當視圖上有50-100個標籤時,while循環的性能如何。 – agarcian 2013-01-31 03:23:52
我從來沒有任何理由去優化它。我不用它來重複計算。唯一的地方,我有很多標籤來選擇最長的標籤文字和尺寸。 – 2014-03-04 12:17:47
@NielsCastle你的解決方案是否也採用了文字包裝技術?我在agarcian的答案中寫了一個案例。它是否也滿足這種情況? – 2014-11-19 01:06:56