这是iPhone应用程序的一部分,但应该适用于一般用objC编写的Cocoa。
我有一个UILabel,持有不同数量的文本(从单个字符到几个句子)。文本应始终以适合UILabel中所有文本的最大可能字体显示。 最大行数设置为4,换行模式设置为自动换行。
由于使用了多行,adjustsFontSizeToFitWidth无法用于调整文本大小。
因此我使用循环来确定每个字符串的最大可能字体大小:
//Set the text self.textLabel.text = text; //Largest size used NSInteger fsize = 200; textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize]; //Calculate size of the rendered string with the current parameters float height = [text sizeWithFont:textLabel.font constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) lineBreakMode:UILineBreakModeWordWrap].height; //Reduce font size by 5 while too large, break if no height (empty string) while (height > textLabel.bounds.size.height and height != 0) { fsize -= 5; textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize]; height = [text sizeWithFont:textLabel.font constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) lineBreakMode:UILineBreakModeWordWrap].height; };
这种方法在大多数情况下都很有效。 例外是长话。 让我们来看看@“体验foo”。举个例子。 “经验”这个词,比其他人长得多,将被分成两半,而不是正确地换行,字符串分为4行。 我正在寻找一种方法来进一步减小尺寸,以便每个单词都适合一行。
示例:
-old -
字体大小:60
The Exper ience foo
应该是
-new -
字体大小:30
The Experience foo
可能有一种简单的方法可以做到这一点,但我正在撞墙。
答案 0 :(得分:12)
这是我发现这项工作的最优雅(但有些黑客)方式:
资源消耗足够低,即使在UITableViews
以这种方式编辑的字符串中也能正常工作。
这是新代码:
//Set the text
self.textLabel.text = text;
//Largest size used
NSInteger fsize = 200; textLabel.font = [UIFont fontWithName:@"Verdana-Bold"
size:fsize];
//Calculate size of the rendered string with the current parameters
float height =
[text sizeWithFont:textLabel.font
constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999)
lineBreakMode:UILineBreakModeWordWrap].height;
//Reduce font size by 5 while too large, break if no height (empty string)
while (height > textLabel.bounds.size.height and height != 0) {
fsize -= 5;
textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize];
height = [text sizeWithFont:textLabel.font
constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999)
lineBreakMode:UILineBreakModeWordWrap].height;
};
// Loop through words in string and resize to fit
for (NSString *word in [text componentsSeparatedByString:@" "]) {
float width = [word sizeWithFont:textLabel.font].width;
while (width > textLabel.bounds.size.width and width != 0) {
fsize -= 3;
textLabel.font = [UIFont fontWithName:@"Verdana-Bold" size:fsize];
width = [word sizeWithFont:textLabel.font].width;
}
}
答案 1 :(得分:3)
您可以在UILabel的类别中使用上面的代码
的UILabel + AdjustFontSize.h
@interface UILabel (UILabel_AdjustFontSize)
- (void) adjustsFontSizeToFitWidthWithMultipleLinesFromFontWithName:(NSString*)fontName size:(NSInteger)fsize andDescreasingFontBy:(NSInteger)dSize;
@end
的UILabel + AdjustFontSize.m
@implementation UILabel (UILabel_AdjustFontSize)
- (void) adjustsFontSizeToFitWidthWithMultipleLinesFromFontWithName:(NSString*)fontName size:(NSInteger)fsize andDescreasingFontBy:(NSInteger)dSize{
//Largest size used
self.font = [UIFont fontWithName:fontName size:fsize];
//Calculate size of the rendered string with the current parameters
float height = [self.text sizeWithFont:self.font
constrainedToSize:CGSizeMake(self.bounds.size.width,99999)
lineBreakMode:UILineBreakModeWordWrap].height;
//Reduce font size by dSize while too large, break if no height (empty string)
while (height > self.bounds.size.height && height != 0) {
fsize -= dSize;
self.font = [UIFont fontWithName:fontName size:fsize];
height = [self.text sizeWithFont:self.font
constrainedToSize:CGSizeMake(self.bounds.size.width,99999)
lineBreakMode:UILineBreakModeWordWrap].height;
};
// Loop through words in string and resize to fit
for (NSString *word in [self.text componentsSeparatedByString:@" "]) {
float width = [word sizeWithFont:self.font].width;
while (width > self.bounds.size.width && width != 0) {
fsize -= dSize;
self.font = [UIFont fontWithName:fontName size:fsize];
width = [word sizeWithFont:self.font].width;
}
}
}
@end
答案 2 :(得分:3)
这是我的版本0x90在一个类别中的答案:
@implementation UILabel (MultilineAutosize)
- (void)adjustFontSizeToFit
{
//Largest size used
NSInteger fsize = self.font.pointSize;
//Calculate size of the rendered string with the current parameters
float height = [self.text sizeWithFont:self.font
constrainedToSize:CGSizeMake(self.bounds.size.width, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping].height;
//Reduce font size by 5 while too large, break if no height (empty string)
while (height > self.bounds.size.height && height > 0) {
fsize -= 5;
self.font = [self.font fontWithSize:fsize];
height = [self.text sizeWithFont:self.font
constrainedToSize:CGSizeMake(self.bounds.size.width, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping].height;
};
// Loop through words in string and resize to fit
for (NSString *word in [self.text componentsSeparatedByString:@" "]) {
float width = [word sizeWithFont:self.font].width;
while (width > self.bounds.size.width && width > 0) {
fsize -= 3;
self.font = [self.font fontWithSize:fsize];
width = [word sizeWithFont:self.font].width;
}
}
}
@end
答案 3 :(得分:0)
这是一个很大的问题,您可能会认为,使用尽可能大的字体大小而不破坏单词将成为内置UIKit
功能或相关框架的一部分。这是一个很好的视觉问题示例:
正如其他人所描述的,诀窍是对单个单词以及整个文本进行大小搜索。这是因为当您指定一个宽度来绘制单个单词时,大小调整方法会将这些单词分解,因为它们别无选择-您要它们将具有特定字体大小的“坚不可摧”的字符串绘制到一个区域中那根本不合适。
在我的工作解决方案的核心,我使用以下二进制搜索功能:
func binarySearch(string: NSAttributedString, minFontSize: CGFloat, maxFontSize: CGFloat, maxSize: CGSize, options: NSStringDrawingOptions) -> CGFloat {
let avgSize = roundedFontSize((minFontSize + maxFontSize) / 2)
if avgSize == minFontSize || avgSize == maxFontSize { return minFontSize }
let singleLine = !options.contains(.usesLineFragmentOrigin)
let canvasSize = CGSize(width: singleLine ? .greatestFiniteMagnitude : maxSize.width, height: .greatestFiniteMagnitude)
if maxSize.contains(string.withFontSize(avgSize).boundingRect(with: canvasSize, options: options, context: nil).size) {
return binarySearch(string: string, minFontSize:avgSize, maxFontSize:maxFontSize, maxSize: maxSize, options: options)
} else {
return binarySearch(string: string, minFontSize:minFontSize, maxFontSize:avgSize, maxSize: maxSize, options: options)
}
}
但是,仅此一项是不够的。您需要使用它来首先找到适合边界内最长单词的最大大小。一旦有了,就继续搜索较小的字体,直到整个文本适合为止。这样一来,任何话都不会被打破。还有一些更多的注意事项,包括找出最长的单词实际上是什么(有些陷阱!)和iOS字体缓存性能。
如果您只想以简单的方式在屏幕上显示文本,那么我已经在Swift中开发了一个可靠的实现,我还在生产应用程序中使用了该实现。这是一个UIView
子类,可对任何输入文本(包括多行)进行高效,自动的字体缩放。要使用它,您只需执行以下操作即可:
let view = AKTextView()
// Use a simple or fancy NSAttributedString
view.attributedText = .init(string: "Some text here")
// Add to the view hierarchy somewhere
就是这样!您可以在此处找到完整的源代码:https://github.com/FlickType/AccessibilityKit
希望这会有所帮助!
答案 4 :(得分:0)
Swift 4中的UILabel扩展基于0x90的答案:
func adjustFontSizeToFit() {
guard var font = self.font, let text = self.text else { return }
let size = self.frame.size
var maxSize = font.pointSize
while maxSize >= self.minimumScaleFactor * self.font.pointSize {
font = font.withSize(maxSize)
let constraintSize = CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude)
let textRect = (text as NSString).boundingRect(with: constraintSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : font], context: nil)
let labelSize = textRect.size
if labelSize.height <= size.height {
self.font = font
self.setNeedsLayout()
break
}
maxSize -= 1
}
self.font = font;
self.setNeedsLayout()
}