UILabel이 잘 렸는지 확인하는 방법은 무엇입니까?


105

나는이 UILabel변화 할 수있는 길이 내 애플 아이폰이나 아이 패드에 세로 또는 가로 모드로 실행 여부에 따라 달라집니다. 텍스트가 너무 길어서 한 줄에 표시 할 수없고 잘릴 때 사용자가 텍스트를 눌러 전체 텍스트 팝업을 볼 수 있기를 바랍니다.

UILabel이 텍스트가 잘리는 지 어떻게 확인할 수 있습니까? 가능할까요? 지금은 내가 어떤 모드에 있는지에 따라 다른 길이를 확인하고 있지만 잘 작동하지 않습니다.


1
내가 여기에
Claus

몇 년이 지난 후에도 애플이 UILabelAPI에 이와 같은 기본적인 것을 통합하지 않았다는 사실을 믿을 수 없습니다 .
funct7

답변:


108

문자열너비를 계산하고 너비가 다음보다 큰지 확인할 수 있습니다.label.bounds.size.width

NSString UIKit Additions 에는 특정 글꼴로 문자열의 크기를 계산하는 몇 가지 방법이 있습니다. 그러나 시스템에서 해당 크기로 텍스트를 축소 할 수 있도록 레이블에 대한 minimumFontSize가있는 경우. 이 경우 sizeWithFont : minFontSize : actualFontSize : forWidth : lineBreakMode : 를 사용할 수 있습니다 .

CGSize size = [label.text sizeWithAttributes:@{NSFontAttributeName:label.font}];
if (size.width > label.bounds.size.width) {
   ...
}

1
고마워요, 이것이 제가 필요한 것입니다. 유일한 차이점은 sizeWithFont :는 CGSize를 반환한다는 것입니다.
Randall

아, 지적 해주셔서 감사합니다. 샘플 코드를 수정했습니다.
progrmr

16
sizeWithFont는 더 이상 사용되지 않습니다. 사용 : [label.text sizeWithAttributes : @ {NSFontAttributeName : label.font}];
Amelia777 2014-07-25

2
@fatuhoku numberOfLinesUILabel클래스 참조에 설명 된대로 텍스트를 표시하는 데 사용되는 최대 줄 수를 반환합니다 . developer.apple.com/library/ios/documentation/UIKit/Reference/…
Paul

1
라벨에 줄 수가 있으면 다음과 같이 너비를 줄 수로 곱하십시오 if (size.width> label.bounds.size.width * label.numberOfLines) {...}
Fadi Abuzant

89

Swift (확장자)-여러 줄 uilabel에서 작동합니다.

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 :

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 :

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
    }

}

999999.0의 높이를 CGFloat (FLT_MAX)로 대체
주변 광

2
신속한 3의 경우 CGFloat.greatestFiniteMagnitude를 사용합니다
zero3nna

2
좋은 대답이지만 func 대신 계산 된 속성을 사용하는 것이 더 좋습니다. var isTruncated : Bool {if let string = self.text {let size : CGSize = (string as NSString) .boundingRect (with : CGSize (width : self.frame.size .width, height : CGFloat.greatestFiniteMagnitude), 옵션 : NSStringDrawingOptions.usesLineFragmentOrigin, 속성 : [NSFontAttributeName : self.font], 컨텍스트 : nil) .size return (size.height> self.bounds.size.height)} return false}
Mohammadalijf

1
NSAttributedString을 사용했기 때문에 이것은 나를 위해 작동하지 않았습니다. 작동하도록하려면 속성 값을 다음과 같이 수정해야했습니다. attributeText? .attributes (at : 0, effectiveRange : nil)
pulse4life

1
좋은 대답은 내 요구 사항에 맞게 약간 변경해야했지만 완벽하게 작동했습니다. 나는 또한 속성 문자열을 사용하고 있었다-그래서 내가 사용한 속성 : (attributedText? .attributes (at : 0, effectiveRange : nil) ?? [.font : font]), 그냥 labelText가 비어 있지 않은지 확인하십시오. 이 솔루션을 사용합니다.
Crt Gregoric

20

편집 : 방금 내 대답이 찬성되는 것을 보았지만 내가 준 코드 스 니펫은 더 이상 사용되지 않습니다.
이제이를 수행하는 가장 좋은 방법은 (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");
}

계산 된 크기는 정수 값이 아닙니다. 따라서와 같은 작업을 수행 int height = rect.size.height하면 부동 소수점 정밀도가 손실되고 잘못된 결과가 발생할 수 있습니다.

이전 답변 (지원 중단됨) :

레이블이 여러 줄이면 다음 코드를 사용할 수 있습니다.

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");
}

13

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;
}

3
문서에서 : textRectForBounds:limitedToNumberOfLines:"이 메서드를 직접 호출하면 안됩니다"...
Martin

@Martin 감사합니다. 여기 구현이 제한되어 있습니다.하지만 경계와 텍스트를 설정 한
후이

limitedToNumberOfLines를 설정할 때 왜 +1합니까?
Ash

@Ash는 텍스트에 더 많은 공간이 허용 될 때 레이블이 더 높은지 확인합니다.
vrwim

1
이 코드 덕분에 자동 레이아웃을 사용할 때 일부 테두리 경우를 제외하고 저에게 효과적이었습니다. setNeedsLayout() layoutIfNeeded()메서드 시작 부분에 다음 을 추가하여 수정했습니다 .
Jovan Jovanovski

9

이 카테고리를 사용하여 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

9

스위프트 3

문자열을 할당 한 후 줄 수를 계산하고 레이블의 최대 줄 수와 비교할 수 있습니다.

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
    }
}

이것은 신속하게 좋은 대답입니다. 감사.
JimmyLee

8

에 추가하려면 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;
}

감사! 프레임 대신 intrinsicContentSize를 사용하는 것이 UILabel 높이가 실제로 텍스트에 맞기에 충분하지만 줄 수가 제한되어 있으므로 여전히 잘리는 경우 내 문제에 대한 해결책이었습니다.
Anton Matosov 2015 년

어떤 이유로,이 텍스트가 라벨에 맞지 않는 경우에도 어떠한 반환하지 않습니다
캔 Poyrazoğlu

6

이거 야. 이것은 attributedText일반으로 돌아 가기 전에 와 함께 작동합니다. 이는 text여러 글꼴 패밀리, 크기 및 NSTextAttachments를 다루는 우리에게 많은 의미가 있습니다!

자동 레이아웃과 잘 작동하지만, 확인하기 전에 제약 조건을 정의하고 설정해야합니다 isTruncated. 그렇지 않으면 레이블 자체가 레이아웃 방법을 알지 못하므로 잘 렸는지조차 알 수 없습니다.

일반 NSStringsizeThatFits. 사람들이 어떻게 그렇게 긍정적 인 결과를 얻고 있는지 잘 모르겠습니다. BTW는 여러 번 언급했듯이 결과 크기 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
    }
}

이것은 나를 위해 잘 작동합니다 !! 이것에 대한 업데이트 또는 수정이 있습니까?
amodkanthe

좋은 대답입니다. 유일한 문제는 attributeText는 설정하지 않아도 nil이 아닙니다. 그래서 이것을 두 개의 vars isTextTruncated와 isAttributedTextTruncated로 구현했습니다.
Harris

@Harris는 uilabel.h 파일에서 기본값이 nil이라고 말합니다
Lucas

@LucasChwe 알고 있지만 실제로는 사실이 아닙니다. 직접 시도하고 볼 수 있습니다. 참고로, forums.developer.apple.com/thread/118581
해리스

3

다음은 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
    }
}

Axel의 대답은 이것을 위해 작동하지 않았습니다. 이건 해냈어. 감사!
Glenn

2

이것은 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");
}

2

UILabel의 잘림 작업에 대한 범주를 작성했습니다. iOS 7 이상에서 작동합니다. 도움이 되길 바랍니다! uilabel 꼬리 잘림

@implementation UILabel (Truncation)

- (NSRange)truncatedRange
{
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:[self attributedText]];

    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    [textStorage addLayoutManager:layoutManager];

    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self bounds].size];
    textContainer.lineFragmentPadding = 0;
    [layoutManager addTextContainer:textContainer];

    NSRange truncatedrange = [layoutManager truncatedGlyphRangeInLineFragmentForGlyphAtIndex:0];
    return truncatedrange;
}

- (BOOL)isTruncated
{
    return [self truncatedRange].location != NSNotFound;
}

- (NSString *)truncatedText
{
    NSRange truncatedrange = [self truncatedRange];
    if (truncatedrange.location != NSNotFound)
    {
        return [self.text substringWithRange:truncatedrange];
    }

    return nil;
}

@end

모든 시간 만 NSNotFound을 제공합니다
다리어

2
extension UILabel {

public func resizeIfNeeded() -> CGFloat? {
    guard let text = text, !text.isEmpty else { return nil }

    if isTruncated() {
        numberOfLines = 0
        sizeToFit()
        return frame.height
    }
    return nil
}

func isTruncated() -> Bool {
    guard let text = text, !text.isEmpty else { return false }

    let size: CGSize = text.size(withAttributes: [NSAttributedStringKey.font: font])
    return size.width > self.bounds.size.width
    }
}

문자열의 너비를 계산하고 너비가 레이블 너비보다 큰지 확인할 수 있습니다.


1

무엇에 추가하려면 @iDev이 했다, 나는 수정 self.frame.size.height사용 label.frame.size.height도 사용하지 않았다 NSStringDrawingUsesLineFontLeading. 이러한 수정 후에는 잘림이 발생하는시기를 완벽하게 계산했습니다 (적어도 제 경우에는).

- (BOOL)isTruncated:(UILabel *)label {
    CGSize sizeOfText = [label.text boundingRectWithSize: CGSizeMake(label.bounds.size.width, CGFLOAT_MAX)
                                                 options: (NSStringDrawingUsesLineFragmentOrigin)
                                              attributes: [NSDictionary dictionaryWithObject:label.font forKey:NSFontAttributeName] context: nil].size;

    if (label.frame.size.height < ceilf(sizeOfText.height)) {
        return YES;
    }
    return NO;
}

1

boundingRect(with:options:attributes:context:)자동 레이아웃 을 사용할 때 (최대 높이를 설정하기 위해) 문제가 발생했습니다.NSParagraph.lineSpacing

라인 사이의 간격은 (전달하는 경우에도 무시 attributes받는 boundingRect이 때 잘리지로 라벨이 고려 될 수 있도록 방법).

내가 찾은 해결책은 다음을 사용하는 것입니다 UIView.sizeThatFits.

extension UILabel {
    var isTruncated: Bool {
        layoutIfNeeded()
        let heightThatFits = sizeThatFits(bounds.size).height
        return heightThatFits > bounds.size.height
    }
}

0

위의 모든 답변은 감가 상각 방법을 사용하기 때문에 이것이 유용 할 것이라고 생각했습니다.

- (BOOL)isLabelTruncated:(UILabel *)label
{
    BOOL isTruncated = NO;

    CGRect labelSize = [label.text boundingRectWithSize:CGSizeFromString(label.text) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : label.font} context:nil];

    if (labelSize.size.width / labelSize.size.height > label.numberOfLines) {

        isTruncated = YES;
    }

    return isTruncated;
}

너비를 높이로 나누고 있으며 줄 수보다 크면 (0이 될 수 있음) 레이블이 잘린 것입니다. 이것이 작동하는 방법이 없습니다.
캔 Leloğlu

@ CanLeloğlu 그것을 테스트하십시오. 실제적인 예입니다.
Raz 2015 년

2
numberOfLines가 0이면 어떻게됩니까?
Can Leloğlu 2015 년

0

iOS 6을 처리하기 위해 (예, 우리 중 일부는 여전히 그래야 함) @iDev의 답변에 대한 또 다른 확장이 있습니다. 중요한 점은 iOS 6의 경우 sizeThatFits를 호출하기 전에 UILabel의 numberOfLines가 0으로 설정되어 있는지 확인하는 것입니다. 그렇지 않은 경우 레이블 텍스트를 그리는 데 "높이에 해당하는 numberOfLines를 그리는 점"이 필요하다는 결과가 표시됩니다.

- (BOOL)isTruncated
{
    CGSize sizeOfText;

    // iOS 7 & 8
    if([self.text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)])
    {
        sizeOfText = [self.text boundingRectWithSize:CGSizeMake(self.bounds.size.width,CGFLOAT_MAX)
                                             options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                          attributes:@{NSFontAttributeName:self.font}
                                             context:nil].size;
    }
    // iOS 6
    else
    {
        // For iOS6, set numberOfLines to 0 (i.e. draw label text using as many lines as it takes)
        //  so that siteThatFits works correctly. If we leave it = 1 (for example), it'll come
        //  back telling us that we only need 1 line!
        NSInteger origNumLines = self.numberOfLines;
        self.numberOfLines = 0;
        sizeOfText = [self sizeThatFits:CGSizeMake(self.bounds.size.width,CGFLOAT_MAX)];
        self.numberOfLines = origNumLines;
    }

    return ((self.bounds.size.height < sizeOfText.height) ? YES : NO);
}

0

viewDidLayoutSubviews에서 이들 중 하나를 호출해야합니다.

public extension UILabel {

    var isTextTruncated: Bool {
        layoutIfNeeded()
        return text?.boundingRect(with: CGSize(width: bounds.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font!], context: nil).size.height ?? 0 > bounds.size.height
    }

    var isAttributedTextTruncated: Bool {
        layoutIfNeeded()
        return attributedText?.boundingRect(with: CGSize(width: bounds.width, height: .greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil).size.height ?? 0 > bounds.size.height
    }

}

0

SWIFT 5

3 줄만 표시하도록 설정된 여러 줄 UILabel의 예입니다.

    let labelSize: CGSize = myLabel.text!.size(withAttributes: [.font: UIFont.systemFont(ofSize: 14, weight: .regular)])

    if labelSize.width > myLabel.intrinsicContentSize.width * 3 {
        // your label will truncate
    }

사용자가 "텍스트 너비"를 추가하지 않고 추가 행을 추가하는 리턴 키를 선택할 수 있지만이 경우 이와 같은 것도 유용 할 수 있습니다.

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

    if text == "\n" {
        // return pressed 

    }
}

-1

Swift 3 솔루션

가장 좋은 해결책은 (1)UILabel 잘림을 확인하는 레이블과 동일한 속성으로을 만들고 , (2) 호출하고 .sizeToFit(), (3) 더미 레이블의 속성을 실제 레이블과 비교하는 것입니다.

예를 들어, 너비가 다른 한 줄 레이블이 잘리는 지 여부를 확인하려면 다음 확장을 사용할 수 있습니다.

extension UILabel {
    func isTruncated() -> Bool {
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: CGFloat.greatestFiniteMagnitude, height: self.bounds.height))
        label.numberOfLines = 1
        label.font = self.font
        label.text = self.text
        label.sizeToFit()
        if label.frame.width > self.frame.width {
            return true
        } else {
            return false
        }
    }
}

...하지만 다시 말하지만, 필요에 맞게 위의 코드를 쉽게 수정할 수 있습니다. 라벨이 여러 줄로되어 있고 높이가 다양하다고 가정 해 보겠습니다. 그러면 확장은 다음과 같습니다.

extension UILabel {
    func isTruncated() -> Bool {
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.font = self.font
        label.text = self.text
        label.sizeToFit()
        if label.frame.height > self.frame.height {
            return true
        } else {
            return false
        }
    }
}

-6

레이블에 대한 제목 속성을 설정하는 것은 쉽지 않을 것입니다. 이렇게 설정하면 마우스를 가져 가면 전체 레이블이 표시됩니다.

레이블의 길이와 div 너비를 계산할 수 있습니다 (길이로 변환 -jQuery / Javascript-픽셀 값 (20px)을 숫자 값 (20)으로 변환하는 방법) ).

길이가 div 너비보다 큰 경우 jquery를 설정하여 제목을 설정하십시오.

var divlen = parseInt(jQuery("#yourdivid").width,10);
var lablen =jQuery("#yourlabelid").text().length;
if(lablen < divlen){
jQuery("#yourlabelid").attr("title",jQuery("#yourlabelid").text());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.