如何找到 UILabel 的实际行数?
How to find actual number of lines of UILabel?
在用 text
和 font
初始化后,如何找到 UILabel
的 实际 行数?我已将其 numberOfLines
属性 设置为 0
,因此它会扩展到需要多少行。但是,设置 text
后,如何才能知道它最终得到了多少行呢?
我发现了类似的问题,但 none 似乎提供了一个简明的答案,在我看来,它一定很容易得到它,而不需要在使用 boundingRectWithSize
或sizeWithFont
,...
首先在UILabel中设置文本
第一个选项:
首先根据字体计算文字的高度:
NSInteger lineCount = 0;
CGSize labelSize = (CGSize){yourLabel.frame.size.width, MAXFLOAT};
CGRect requiredSize = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: yourLabel.font} context:nil];
现在计算行数:
int charSize = lroundf(yourLabel.font.lineHeight);
int rHeight = lroundf(requiredSize.height);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);
第二个选项:
NSInteger lineCount = 0;
CGSize textSize = CGSizeMake(yourLabel.frame.size.width, MAXFLOAT);
int rHeight = lroundf([yourLabel sizeThatFits:textSize].height);
int charSize = lroundf(yourLabel.font.lineHeight);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);
根据@Prince 的回答,我现在在 UILabel
上实现了一个 类别 ,如下所示(请注意,我更正了他的回答中的一些小语法错误,这些错误不会让代码编译):
UILabel+Util.h
#import <UIKit/UIKit.h>
@interface UILabel (Util)
- (NSInteger)lineCount;
@end
UILabel+Util.,
#import "UILabel+Util.h"
@implementation UILabel (Util)
- (NSInteger)lineCount
{
// Calculate height text according to font
NSInteger lineCount = 0;
CGSize labelSize = (CGSize){self.frame.size.width, FLT_MAX};
CGRect requiredSize = [self.text boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: self.font} context:nil];
// Calculate number of lines
int charSize = self.font.leading;
int rHeight = requiredSize.size.height;
lineCount = rHeight/charSize;
return lineCount;
}
@end
当 UILabel
的 numberOfLines
属性 设置为 0 以外的值时,这里的其他答案不尊重 numberOfLines
属性。
这是您可以添加到类别或子类中的另一个选项:
- (NSUInteger)lineCount
{
CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
return MAX((int)(size.height / self.font.lineHeight), 0);
}
一些注意事项:
- 我在带有属性文本的 UILabel 上使用它,而没有实际设置
font
属性,它工作正常。如果您在 attributedText
. 中使用多种字体,显然您 运行 会遇到问题
- 如果您将
UILabel
子类化为具有自定义边缘插入(例如通过覆盖 drawTextInRect:
,这是我发现的一个巧妙的技巧 here),那么您必须记住采取在计算上面的 size
时将这些插图考虑在内。例如:CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)
这是@Paresh 解决方案的swift 版本:
func lines(label: UILabel) -> Int {
let textSize = CGSize(width: label.frame.size.width, height: CGFloat(Float.infinity))
let rHeight = lroundf(Float(label.sizeThatFits(textSize).height))
let charSize = lroundf(Float(label.font.lineHeight))
let lineCount = rHeight/charSize
return lineCount
}
编辑:我不知道为什么,但代码返回的行数比实际行数多 2 行,对于我的解决方案,我只是在返回 lineCount 之前减去它们。
这是 Swift3 代码
在这里,您可以定义 Int 值并使用 (MAXFLOAT) 获取文本大小的高度,并使用该高度可以获取 UILabel 的总高度,并通过将总高度除以字符大小来获取 UILabel 的实际行数。
var lineCount: Int = 0
var textSize = CGSize(width: CGFloat(yourLabel.frame.size.width), height: CGFloat(MAXFLOAT))
var rHeight: Int = lroundf(yourLabel.sizeThatFits(textSize).height)
var charSize: Int = lroundf(yourLabel.font.leading)
lineCount = rHeight / charSize
print("No of lines: \(lineCount)")
Swift 5 (IOS 12.2)
Get max number of lines required for a label to render the text without truncation.
extension UILabel {
var maxNumberOfLines: Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
let text = (self.text ?? "") as NSString
let textHeight = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height
let lineHeight = font.lineHeight
return Int(ceil(textHeight / lineHeight))
}
}
Get max number of lines can be displayed in a label with constrained bounds. Use this property after assigning text to label.
extension UILabel {
var numberOfVisibleLines: Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
let textHeight = sizeThatFits(maxSize).height
let lineHeight = font.lineHeight
return Int(ceil(textHeight / lineHeight))
}
}
用法
print(yourLabel.maxNumberOfLines)
print(yourLabel.numberOfVisibleLines)
您可以找到自定义标签中可用的总行数
请检查此代码...
NSInteger numberOfLines = [self lineCountForText:@"YOUR TEXT"];
- (int)lineCountForText:(NSString *) text
{
UIFont *font = [UIFont systemFontOfSize: 15.0];
int width=Your_LabelWidht;
CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil];
return ceil(rect.size.height / font.lineHeight);
}
Xamarin iOS
label.Text = text;
var lineCount = 0;
var textSize = new CGSize(label.Frame.Size.Width, float.MaxValue);
var height = label.SizeThatFits(textSize).Height;
var fontHeight = label.Font.LineHeight;
lineCount = Convert.ToInt32(height / fontHeight);
None 其中对我有用。下面一个做了,
Swift 4.2:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Swift 4/4.1:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Swift 3:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Xamarin.iOS
感谢楼上大家的回答
这会获取可见行数。
public static int VisibleLineCount(this UILabel label)
{
var textSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
nfloat rHeight = label.SizeThatFits(textSize).Height;
nfloat charSize = label.Font.LineHeight;
return Convert.ToInt32(rHeight / charSize);
}
这会获取文本将在屏幕上占据的实际行数。
public static int LineCount(this UILabel label)
{
var maxSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
var charSize = label.Font.LineHeight;
var text = (label.Text ?? "").ToNSString();
var textSize = text.GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, new UIStringAttributes() { Font = label.Font }, null);
return Convert.ToInt32(textSize.Height / charSize);
}
我发现对我的用例有用的辅助方法。
public static bool IsTextTruncated(this UILabel label)
{
if (label.Lines == 0)
{
return false;
}
return (label.LineCount() > label.Lines);
}
要获得更准确的行数:
- 使用
font.lineHeight
代替font.pointSize
- round() 除法后的行数
let l = UILabel()
l.numberOfLines = 0
l.layer.frame.size.width = self.view.frame.width - 40 /*padding(20 + 20)*/
l.font = UIFont(name: "BwModelica-Bold", size: 16.0)
l.text = "Random Any length Text!!"
let noOfLines = ceil(l.intrinsicContentSize.width / l.frame.size.width)
let lbl_height = noOfLines * l.intrinsicContentSize.height
这将是您的标签的精确动态高度和行数。编码愉快!!!
请注意@kurt-j 的回答并不总是有效。在某些情况下,您必须手动提供标签的宽度。由于存在这些情况,最好有一个可选的宽度参数,即使您最终没有使用它。
Swift 4.2:
extension UILabel {
func calculateMaxLines(actualWidth: CGFloat?) -> Int {
var width = frame.size.width
if let actualWidth = actualWidth {
width = actualWidth
}
let maxSize = CGSize(width: width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
官方开发者网站似乎提到了Objc中的一种解决方案Counting Lines of Text。但是,它假定您有一个对配置有布局管理器、文本存储和文本容器的文本视图的引用。不幸的是,UILabel 不会向我们公开这些,因此我们需要使用与 UILabel 相同的配置来创建它们。
我将 Objc 代码翻译成 swift,如下所示。它似乎很适合我。
extension UILabel {
var actualNumberOfLines: Int {
let textStorage = NSTextStorage(attributedString: self.attributedText!)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.bounds.size)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = self.lineBreakMode
layoutManager.addTextContainer(textContainer)
let numberOfGlyphs = layoutManager.numberOfGlyphs
var numberOfLines = 0, index = 0, lineRange = NSMakeRange(0, 1)
while index < numberOfGlyphs {
layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
}
Swift 5.2
让它对我有用的要点是调用 label.layoutIfNeeded() 因为我使用的是 autoLayout,否则它不起作用。
func actualNumberOfLines(label: UILabel) -> Int {
// You have to call layoutIfNeeded() if you are using autoLayout
label.layoutIfNeeded()
let myText = label.text! as NSString
let rect = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: label.font as Any], context: nil)
return Int(ceil(CGFloat(labelSize.height) / label.font.lineHeight))
}
致谢:https://gist.github.com/fuxingloh/ccf26bb68f4b8e6cfd02,它在较旧的 swift 版本中提供了解决方案,并提到了 layoutIfNeeded() 的重要性。
⚠️ 、lineHeight
、leading
都不够。
font.lineHeight
是字形的高度,它从descender
(最低字形的底部)到ascender
(最高字形的顶部)。另外,请注意 lineHeight
可以覆盖属性字符串。 font.leading
是 (!) 行之间的附加(虽然可能是负数)space(请自行查看文档)。如果您使用系统字体,几乎每个磅值都会得到不同的前导值。
例如具有 5 行的标签的高度由 5 lineHeight
和 4 leading
组成(但主值通常小到足以使上述解决方案工作,直到您开始使用多行。
所以正确的(伪)公式应该是:
(frame.size.height + font.leading) / (font.lineHeight + font.leading)
Also also, if the attributed string has an attachment that is too big (higher than the ascender
of the font), then it also alters the line height for that row.
Swift 5.4
Fernando Cardenas对UILabel扩展的重构方案
private extension UILabel {
var actualNumberOfLines: Int {
guard let text = self.text else {
return 0
}
layoutIfNeeded()
let rect = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = text.boundingRect(
with: rect,
options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font as Any],
context: nil)
return Int(ceil(CGFloat(labelSize.height) / font.lineHeight))
}
}
在用 text
和 font
初始化后,如何找到 UILabel
的 实际 行数?我已将其 numberOfLines
属性 设置为 0
,因此它会扩展到需要多少行。但是,设置 text
后,如何才能知道它最终得到了多少行呢?
我发现了类似的问题,但 none 似乎提供了一个简明的答案,在我看来,它一定很容易得到它,而不需要在使用 boundingRectWithSize
或sizeWithFont
,...
首先在UILabel中设置文本
第一个选项:
首先根据字体计算文字的高度:
NSInteger lineCount = 0;
CGSize labelSize = (CGSize){yourLabel.frame.size.width, MAXFLOAT};
CGRect requiredSize = [self boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: yourLabel.font} context:nil];
现在计算行数:
int charSize = lroundf(yourLabel.font.lineHeight);
int rHeight = lroundf(requiredSize.height);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);
第二个选项:
NSInteger lineCount = 0;
CGSize textSize = CGSizeMake(yourLabel.frame.size.width, MAXFLOAT);
int rHeight = lroundf([yourLabel sizeThatFits:textSize].height);
int charSize = lroundf(yourLabel.font.lineHeight);
lineCount = rHeight/charSize;
NSLog(@"No of lines: %i",lineCount);
根据@Prince 的回答,我现在在 UILabel
上实现了一个 类别 ,如下所示(请注意,我更正了他的回答中的一些小语法错误,这些错误不会让代码编译):
UILabel+Util.h
#import <UIKit/UIKit.h>
@interface UILabel (Util)
- (NSInteger)lineCount;
@end
UILabel+Util.,
#import "UILabel+Util.h"
@implementation UILabel (Util)
- (NSInteger)lineCount
{
// Calculate height text according to font
NSInteger lineCount = 0;
CGSize labelSize = (CGSize){self.frame.size.width, FLT_MAX};
CGRect requiredSize = [self.text boundingRectWithSize:labelSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: self.font} context:nil];
// Calculate number of lines
int charSize = self.font.leading;
int rHeight = requiredSize.size.height;
lineCount = rHeight/charSize;
return lineCount;
}
@end
当 UILabel
的 numberOfLines
属性 设置为 0 以外的值时,这里的其他答案不尊重 numberOfLines
属性。
这是您可以添加到类别或子类中的另一个选项:
- (NSUInteger)lineCount
{
CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
return MAX((int)(size.height / self.font.lineHeight), 0);
}
一些注意事项:
- 我在带有属性文本的 UILabel 上使用它,而没有实际设置
font
属性,它工作正常。如果您在attributedText
. 中使用多种字体,显然您 运行 会遇到问题
- 如果您将
UILabel
子类化为具有自定义边缘插入(例如通过覆盖drawTextInRect:
,这是我发现的一个巧妙的技巧 here),那么您必须记住采取在计算上面的size
时将这些插图考虑在内。例如:CGSizeMake(self.frame.size.width - (self.insets.left + self.insets.right), CGFLOAT_MAX)
这是@Paresh 解决方案的swift 版本:
func lines(label: UILabel) -> Int {
let textSize = CGSize(width: label.frame.size.width, height: CGFloat(Float.infinity))
let rHeight = lroundf(Float(label.sizeThatFits(textSize).height))
let charSize = lroundf(Float(label.font.lineHeight))
let lineCount = rHeight/charSize
return lineCount
}
编辑:我不知道为什么,但代码返回的行数比实际行数多 2 行,对于我的解决方案,我只是在返回 lineCount 之前减去它们。
这是 Swift3 代码 在这里,您可以定义 Int 值并使用 (MAXFLOAT) 获取文本大小的高度,并使用该高度可以获取 UILabel 的总高度,并通过将总高度除以字符大小来获取 UILabel 的实际行数。
var lineCount: Int = 0
var textSize = CGSize(width: CGFloat(yourLabel.frame.size.width), height: CGFloat(MAXFLOAT))
var rHeight: Int = lroundf(yourLabel.sizeThatFits(textSize).height)
var charSize: Int = lroundf(yourLabel.font.leading)
lineCount = rHeight / charSize
print("No of lines: \(lineCount)")
Swift 5 (IOS 12.2)
Get max number of lines required for a label to render the text without truncation.
extension UILabel {
var maxNumberOfLines: Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
let text = (self.text ?? "") as NSString
let textHeight = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height
let lineHeight = font.lineHeight
return Int(ceil(textHeight / lineHeight))
}
}
Get max number of lines can be displayed in a label with constrained bounds. Use this property after assigning text to label.
extension UILabel {
var numberOfVisibleLines: Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(MAXFLOAT))
let textHeight = sizeThatFits(maxSize).height
let lineHeight = font.lineHeight
return Int(ceil(textHeight / lineHeight))
}
}
用法
print(yourLabel.maxNumberOfLines)
print(yourLabel.numberOfVisibleLines)
您可以找到自定义标签中可用的总行数 请检查此代码...
NSInteger numberOfLines = [self lineCountForText:@"YOUR TEXT"];
- (int)lineCountForText:(NSString *) text
{
UIFont *font = [UIFont systemFontOfSize: 15.0];
int width=Your_LabelWidht;
CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : font} context:nil];
return ceil(rect.size.height / font.lineHeight);
}
Xamarin iOS
label.Text = text;
var lineCount = 0;
var textSize = new CGSize(label.Frame.Size.Width, float.MaxValue);
var height = label.SizeThatFits(textSize).Height;
var fontHeight = label.Font.LineHeight;
lineCount = Convert.ToInt32(height / fontHeight);
None 其中对我有用。下面一个做了,
Swift 4.2:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Swift 4/4.1:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Swift 3:
extension UILabel {
func calculateMaxLines() -> Int {
let maxSize = CGSize(width: frame.size.width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
Xamarin.iOS
感谢楼上大家的回答
这会获取可见行数。
public static int VisibleLineCount(this UILabel label)
{
var textSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
nfloat rHeight = label.SizeThatFits(textSize).Height;
nfloat charSize = label.Font.LineHeight;
return Convert.ToInt32(rHeight / charSize);
}
这会获取文本将在屏幕上占据的实际行数。
public static int LineCount(this UILabel label)
{
var maxSize = new CGSize(label.Frame.Size.Width, nfloat.MaxValue);
var charSize = label.Font.LineHeight;
var text = (label.Text ?? "").ToNSString();
var textSize = text.GetBoundingRect(maxSize, NSStringDrawingOptions.UsesLineFragmentOrigin, new UIStringAttributes() { Font = label.Font }, null);
return Convert.ToInt32(textSize.Height / charSize);
}
我发现对我的用例有用的辅助方法。
public static bool IsTextTruncated(this UILabel label)
{
if (label.Lines == 0)
{
return false;
}
return (label.LineCount() > label.Lines);
}
要获得更准确的行数:
- 使用
font.lineHeight
代替font.pointSize
- round() 除法后的行数
let l = UILabel()
l.numberOfLines = 0
l.layer.frame.size.width = self.view.frame.width - 40 /*padding(20 + 20)*/
l.font = UIFont(name: "BwModelica-Bold", size: 16.0)
l.text = "Random Any length Text!!"
let noOfLines = ceil(l.intrinsicContentSize.width / l.frame.size.width)
let lbl_height = noOfLines * l.intrinsicContentSize.height
这将是您的标签的精确动态高度和行数。编码愉快!!!
请注意@kurt-j 的回答并不总是有效。在某些情况下,您必须手动提供标签的宽度。由于存在这些情况,最好有一个可选的宽度参数,即使您最终没有使用它。
Swift 4.2:
extension UILabel {
func calculateMaxLines(actualWidth: CGFloat?) -> Int {
var width = frame.size.width
if let actualWidth = actualWidth {
width = actualWidth
}
let maxSize = CGSize(width: width, height: CGFloat(Float.infinity))
let charSize = font.lineHeight
let text = (self.text ?? "") as NSString
let textSize = text.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
let linesRoundedUp = Int(ceil(textSize.height/charSize))
return linesRoundedUp
}
}
官方开发者网站似乎提到了Objc中的一种解决方案Counting Lines of Text。但是,它假定您有一个对配置有布局管理器、文本存储和文本容器的文本视图的引用。不幸的是,UILabel 不会向我们公开这些,因此我们需要使用与 UILabel 相同的配置来创建它们。
我将 Objc 代码翻译成 swift,如下所示。它似乎很适合我。
extension UILabel {
var actualNumberOfLines: Int {
let textStorage = NSTextStorage(attributedString: self.attributedText!)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: self.bounds.size)
textContainer.lineFragmentPadding = 0
textContainer.lineBreakMode = self.lineBreakMode
layoutManager.addTextContainer(textContainer)
let numberOfGlyphs = layoutManager.numberOfGlyphs
var numberOfLines = 0, index = 0, lineRange = NSMakeRange(0, 1)
while index < numberOfGlyphs {
layoutManager.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
index = NSMaxRange(lineRange)
numberOfLines += 1
}
return numberOfLines
}
}
Swift 5.2
让它对我有用的要点是调用 label.layoutIfNeeded() 因为我使用的是 autoLayout,否则它不起作用。
func actualNumberOfLines(label: UILabel) -> Int {
// You have to call layoutIfNeeded() if you are using autoLayout
label.layoutIfNeeded()
let myText = label.text! as NSString
let rect = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: label.font as Any], context: nil)
return Int(ceil(CGFloat(labelSize.height) / label.font.lineHeight))
}
致谢:https://gist.github.com/fuxingloh/ccf26bb68f4b8e6cfd02,它在较旧的 swift 版本中提供了解决方案,并提到了 layoutIfNeeded() 的重要性。
⚠️ 、lineHeight
、leading
都不够。
font.lineHeight
是字形的高度,它从descender
(最低字形的底部)到ascender
(最高字形的顶部)。另外,请注意 lineHeight
可以覆盖属性字符串。 font.leading
是 (!) 行之间的附加(虽然可能是负数)space(请自行查看文档)。如果您使用系统字体,几乎每个磅值都会得到不同的前导值。
例如具有 5 行的标签的高度由 5 lineHeight
和 4 leading
组成(但主值通常小到足以使上述解决方案工作,直到您开始使用多行。
所以正确的(伪)公式应该是:
(frame.size.height + font.leading) / (font.lineHeight + font.leading)
Also also, if the attributed string has an attachment that is too big (higher than the
ascender
of the font), then it also alters the line height for that row.
Swift 5.4 Fernando Cardenas对UILabel扩展的重构方案
private extension UILabel {
var actualNumberOfLines: Int {
guard let text = self.text else {
return 0
}
layoutIfNeeded()
let rect = CGSize(width: bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = text.boundingRect(
with: rect,
options: .usesLineFragmentOrigin,
attributes: [NSAttributedString.Key.font: font as Any],
context: nil)
return Int(ceil(CGFloat(labelSize.height) / font.lineHeight))
}
}