ios 在多行的 UILabel 上自动收缩
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9059631/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Autoshrink on a UILabel with multiple lines
提问by jfisk
Is it possible to use the autoshrink property in conjunction on multiple lines on a UILabel
? for example, the large text size possible on 2 available lines.
是否可以在 a 上的多行上结合使用 autoshrink 属性UILabel
?例如,在 2 个可用行上可能的大文本大小。
采纳答案by The dude
These people found a solution:
这些人找到了解决办法:
http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/
http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/
Their solution is as follows:
他们的解决方法如下:
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;
In order to get this working, a IBOutlet must be assigned in the interface builder to the UILabel.
为了使其工作,必须在界面构建器中将 IBOutlet 分配给 UILabel。
"IBOutlet UILabel *msg;"
"IBOutlet UILabel *msg;"
All the merit is of the people at 11pixel.
所有的优点都是 11pixel 的人。
回答by DaGaMs
I modified the above code somewhat to make it a category on UILabel
:
我稍微修改了上面的代码,使它成为一个类别UILabel
:
Header file:
头文件:
#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
- (void)adjustFontSizeToFit;
@end
And the implementation file:
和实现文件:
@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
回答by MontiRabbit
I found this link http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/
我找到了这个链接http://beckyhansmeyer.com/2015/04/09/autoshrinking-text-in-a-multiline-uilabel/
The problem can be solved using the Interface Builder in 3 simple steps:
使用 Interface Builder 可以通过 3 个简单的步骤解决这个问题:
- Set “Autoshrink” to “Minimum font size.”
- Set the font to your largest desirable font size (20) and set Lines to, say, 10, which in my case was as many lines as would fit in the label at that font size.
- Then, change “Line Breaks” from “Word Wrap” to “Truncate Tail.”
- 将“自动收缩”设置为“最小字体大小”。
- 将字体设置为所需的最大字体大小 (20) 并将 Lines 设置为 10,在我的情况下,这与该字体大小的标签中的行数一样多。
- 然后,将“换行符”从“自动换行”更改为“截尾”。
Hope it helps!
希望能帮助到你!
回答by stevenpaulr
Here's the category solution updated to iOS 7 based off of itecedor's updates for iOS 6.
这是基于 itecedor 对 iOS 6 的更新更新到 iOS 7 的类别解决方案。
Header file:
头文件:
#import <UIKit/UIKit.h>
@interface UILabel (MultiLineAutoSize)
- (void)adjustFontSizeToFit;
@end
And the implementation file:
和实现文件:
@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
回答by GoldenJoe
The answer marked as the solution is hacky and imprecise. UILabel will handle it automatically if you set the following properties correctly:
标记为解决方案的答案是hacky 和不精确的。如果您正确设置以下属性,UILabel 将自动处理它:
numberOfLines
must be nonzero
numberOfLines
必须非零
adjustsFontSizeToFitWidth
must be YES
adjustsFontSizeToFitWidth
必须是 YES
lineBreakMode
must notbe NSLineBreakByCharWrapping
or NSLineBreakByWordWrapping
lineBreakMode
一定不能是NSLineBreakByCharWrapping
或NSLineBreakByWordWrapping
回答by Nem
I cannot comment the post of MontiRabbit due to reputation lacking, so i'll make a new answer. The solution he (and her referrer) proposed do not work on Xcode 7.3 or better, it's imprecise. To make it work, in storyboard, I had to:
由于缺乏声誉,我无法评论MontiRabbit的帖子,所以我会做出一个新的答案。他(和她的推荐人)提出的解决方案不适用于 Xcode 7.3 或更高版本,这是不精确的。为了使它工作,在故事板中,我必须:
- Set a width constraint (pure width or tail&lead)
- SET an HEIGHT CONSTRAINT (this is very important, normally with autoresize one does not set the label height)
- Set "Autoshrink" property to "Minimum font scale" or "Minimum font size" (works in both cases)
- Set "Line Breaks" property to "Truncate Tail"
- Set "Lines" property to a non-zero value
- 设置宽度约束(纯宽度或尾部和前导)
- SET an HEIGHT CONSTRAINT(这很重要,通常使用 autoresize 不会设置标签高度)
- 将“Autoshrink”属性设置为“Minimum font scale”或“Minimum font size”(适用于两种情况)
- 将“换行符”属性设置为“截断尾部”
- 将“Lines”属性设置为非零值
Hope it helps! ;)
希望能帮助到你!;)
回答by wfbarksdale
A swifty version adapted from @DaGaMs.
改编自 @DaGaMs 的 swifty 版本。
SWIFT 2:
快速 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:
快速 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;
}
}
}
}
回答by Abras
itedcedor's answer has an issue that pwightman pointed out. Also, there is no need to trim whitespaces. Here it is the modified version:
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];
}
回答by john.k.doe
i liked DaGaMs's answer, but in using labels like in UITableViewCells that could be returned of dequeueReusableCell:, the regular font size would continue to shrink even as the original font size was still desired for some tableView cells that had less text and could take advantage of the original label's original font size.
我喜欢 DaGaMs 的回答,但是在使用像 UITableViewCells 这样可以从 dequeueReusableCell: 返回的标签时,常规字体大小会继续缩小,即使对于一些文本较少并且可以利用的 tableView 单元格仍然需要原始字体大小原始标签的原始字体大小。
so, i starting with DaGaMs's category as a jumping off point, i created a separate class rather than a separate category, and i make sure my UILabels in my storyboard make use of this new class:
所以,我从 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
回答by itecedor
Thank you to DaGaMs for this solution.
感谢 DaGaMs 提供此解决方案。
I've updated it as follows:
我已将其更新如下:
1 - To work with iOS 6 (since both minimumFontSize and UILineBreakModeWordWrap are deprecated) 2 - To strip whitespace from the label's text, as it will cause the resizing to fail (you don't want to know how long it took me to find that bug)
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];
}