ios 如何检查 UILabel 是否被截断?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3077109/
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
How to check if UILabel is truncated?
提问by Randall
I have a UILabel
that can be varying lengths depending on whether or not my app is running in portrait or landscape mode on an iPhone or iPad. When the text is too long to show on one line and it truncates I want the user to be able to press it and get a popup of the full text.
UILabel
根据我的应用程序是在 iPhone 或 iPad 上以纵向还是横向模式运行,我有一个不同的长度。当文本太长而无法在一行上显示并且它被截断时,我希望用户能够按下它并弹出全文。
How can I check to see if the UILabel
is truncating the text? Is it even possible? Right now I'm just checking for different lengths based on what mode I'm in but it does not work super well.
如何检查是否UILabel
正在截断文本?甚至有可能吗?现在我只是根据我所处的模式检查不同的长度,但它不能很好地工作。
回答by progrmr
You can calculate the width of the stringand see if the width is greater than label.bounds.size.width
可以计算字符串的宽度,看看宽度是否大于label.bounds.size.width
NSString UIKit Additionshas several methods for computing the size of the string with a specific font. However, if you have a minimumFontSize for your label that allows the system to shrink the text down to that size. You may want to use sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:in that case.
NSString UIKit Additions有几种方法来计算具有特定字体的字符串的大小。但是,如果您的标签有一个 minimumFontSize 允许系统将文本缩小到该大小。在这种情况下,您可能需要使用sizeWithFont:minFontSize:actualFontSize:forWidth:lineBreakMode:。
CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];
if (size.width > label.bounds.size.width) {
...
}
回答by Robin
Swift (as extension) - works for multi line uilabel:
斯威夫特(如扩展) - 多行的UILabel作品:
swift4: (attributes
param of boundingRect
changed slightly)
swift4:(attributes
参数boundingRect
略有变化)
extension UILabel {
var isTruncated: Bool {
guard let labelText = text else {
return false
}
let labelTextSize = (labelText as NSString).boundingRect(
with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: font],
context: nil).size
return labelTextSize.height > bounds.size.height
}
}
swift3:
迅捷3:
extension UILabel {
var isTruncated: Bool {
guard let labelText = text else {
return false
}
let labelTextSize = (labelText as NSString).boundingRect(
with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [NSFontAttributeName: font],
context: nil).size
return labelTextSize.height > bounds.size.height
}
}
swift2:
快速2:
extension UILabel {
func isTruncated() -> Bool {
if let string = self.text {
let size: CGSize = (string as NSString).boundingRectWithSize(
CGSize(width: self.frame.size.width, height: CGFloat(FLT_MAX)),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: self.font],
context: nil).size
if (size.height > self.bounds.size.height) {
return true
}
}
return false
}
}
回答by Martin
EDIT:I just saw my answer was upvoted, but the code snippet I gave is deprecated.
Now the best way to do this is (ARC) :
编辑:我刚刚看到我的答案被赞成,但我提供的代码片段已被弃用。
现在最好的方法是(ARC):
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.lineBreakMode = mylabel.lineBreakMode;
NSDictionary *attributes = @{NSFontAttributeName : mylabel.font,
NSParagraphStyleAttributeName : paragraph};
CGSize constrainedSize = CGSizeMake(mylabel.bounds.size.width, NSIntegerMax);
CGRect rect = [mylabel.text boundingRectWithSize:constrainedSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributes context:nil];
if (rect.size.height > mylabel.bounds.size.height) {
NSLog(@"TOO MUCH");
}
Note the calculated size is not integer value. So if you do things like int height = rect.size.height
, you will lose some floating point precision and may have wrong results.
请注意,计算出的大小不是整数值。所以如果你做类似的事情int height = rect.size.height
,你会失去一些浮点精度并且可能会得到错误的结果。
Old answer(deprecated) :
旧答案(已弃用):
If your label is multiline, you can use this code :
如果您的标签是多行的,您可以使用以下代码:
CGSize perfectSize = [mylabel.text sizeWithFont:mylabel.font constrainedToSize:CGSizeMake(mylabel.bounds.size.width, NSIntegerMax) lineBreakMode:mylabel.lineBreakMode];
if (perfectSize.height > mylabel.bounds.size.height) {
NSLog(@"TOO MUCH");
}
回答by DongXu
you can make a category with UILabel
你可以用 UILabel 创建一个类别
- (BOOL)isTextTruncated
{
CGRect testBounds = self.bounds;
testBounds.size.height = NSIntegerMax;
CGRect limitActual = [self textRectForBounds:[self bounds] limitedToNumberOfLines:self.numberOfLines];
CGRect limitTest = [self textRectForBounds:testBounds limitedToNumberOfLines:self.numberOfLines + 1];
return limitTest.size.height>limitActual.size.height;
}
回答by Rajesh
Use this category to find if a label is truncated on iOS 7 and above.
使用此类别可查找标签是否在 iOS 7 及更高版本上被截断。
// UILabel+Truncation.h
@interface UILabel (Truncation)
@property (nonatomic, readonly) BOOL isTruncated;
@end
// UILabel+Truncation.m
@implementation UILabel (Truncation)
- (BOOL)isTruncated
{
CGSize sizeOfText =
[self.text boundingRectWithSize:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{ NSFontAttributeName : label.font }
context: nil].size;
if (self.frame.size.height < ceilf(sizeOfText.height))
{
return YES;
}
return NO;
}
@end
回答by Claus
Swift 3
斯威夫特 3
You can count the number of lines after assigning the string and compare to the max number of lines of the label.
您可以在分配字符串后计算行数并与标签的最大行数进行比较。
import Foundation
import UIKit
extension UILabel {
func countLabelLines() -> Int {
// Call self.layoutIfNeeded() if your view is uses auto layout
let myText = self.text! as NSString
let attributes = [NSFontAttributeName : self.font]
let labelSize = myText.boundingRect(with: CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: attributes, context: nil)
return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
}
func isTruncated() -> Bool {
if (self.countLabelLines() > self.numberOfLines) {
return true
}
return false
}
}
回答by onmyway133
To add to iDev's answer, you should use intrinsicContentSize
instead of frame
, to make it works for Autolayout
要添加到iDev的答案中,您应该使用intrinsicContentSize
而不是frame
, 使其适用于自动布局
- (BOOL)isTruncated:(UILabel *)label{
CGSize sizeOfText = [label.text boundingRectWithSize: CGSizeMake(label.intrinsicContentSize.width, CGFLOAT_MAX)
options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes: [NSDictionary dictionaryWithObject:label.font forKey:NSFontAttributeName] context: nil].size;
if (self.intrinsicContentSize.height < ceilf(sizeOfText.height)) {
return YES;
}
return NO;
}
回答by Lucas Chwe
This is it. This works with attributedText
, before falling back to plain text
, which makes a lot of sense for us folks who deal with multiple font families, sizes, and even NSTextAttachments!
就是这个。这适用于attributedText
, 在回退到 plain 之前text
,这对于我们处理多种字体系列、大小甚至 NSTextAttachments 的人来说很有意义!
Works fine with autolayout, but obviously the constraints must be defined and set before we check isTruncated
, otherwise the label itself wont even know how to lay itself out, so no way it would even know if its truncated.
自动布局工作正常,但显然必须在我们检查之前定义和设置约束isTruncated
,否则标签本身甚至不知道如何布局,所以它甚至不知道它是否被截断。
It doesnt work to approach this problem with just a plain NSString
and sizeThatFits
. Im not sure how people were getting positive results like that. BTW, as mentioned numerous times, using sizeThatFits
is not ideal at all because it takes into account numberOfLines
for the resulting size, which defeats the whole purpose of what we are trying to do, because isTruncated
would always return false
regardless if its truncated or not.
仅使用简单的NSString
和sizeThatFits
. 我不确定人们是如何获得这样的积极结果的。顺便说一句,正如多次提到的那样,使用sizeThatFits
根本不是理想的,因为它考虑numberOfLines
了结果大小,这违背了我们试图做的整个目的,因为无论是否被截断,它isTruncated
总是会返回false
。
extension UILabel {
var isTruncated: Bool {
layoutIfNeeded()
let rectBounds = CGSize(width: bounds.width, height: .greatestFiniteMagnitude)
var fullTextHeight: CGFloat?
if attributedText != nil {
fullTextHeight = attributedText?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, context: nil).size.height
} else {
fullTextHeight = text?.boundingRect(with: rectBounds, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil).size.height
}
return (fullTextHeight ?? 0) > bounds.size.height
}
}
回答by Marcio Fonseca
This works for iOS 8:
这适用于 iOS 8:
CGSize size = [label.text boundingRectWithSize:CGSizeMake(label.bounds.size.width, NSIntegerMax) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : label.font} context:nil].size;
if (size.height > label.frame.size.height) {
NSLog(@"truncated");
}
回答by Travis M.
Here's the selected answer in Swift 3 (as an extension). The OP was asking about 1 line labels. Many of the swift answers I tried here are specific to multi-line labels and aren't flagging correctly on single line labels.
这是 Swift 3 中的选定答案(作为扩展)。OP 询问了 1 个行标签。我在这里尝试的许多快速答案都特定于多行标签,并且在单行标签上没有正确标记。
extension UILabel {
var isTruncated: Bool {
guard let labelText = text as? NSString else {
return false
}
let size = labelText.size(attributes: [NSFontAttributeName: font])
return size.width > self.bounds.width
}
}