programing

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

jooyons 2023. 6. 9. 22:02
반응형

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

나는 있습니다UILabel앱이 iPhone 또는 iPad에서 세로 모드 또는 가로 모드로 실행되는지 여부에 따라 길이가 달라질 수 있습니다.텍스트가 너무 길어서 한 줄에 표시되지 않고 잘린 경우 사용자가 해당 텍스트를 누르고 전체 텍스트 팝업을 표시할 수 있기를 바랍니다.

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

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

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

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

Swift(확장자로 사용) - 다중 줄 ilabel에 대해 작동합니다.

(swift4: ()attributesboundingRect)

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
    }

}

편집: 방금 제 답변이 투표된 것을 보았습니다만, 제가 제공한 코드 조각은 사용되지 않습니다.
방법은 (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");
}

계산된 크기는 정수 값이 아닙니다.그래서 만약 당신이 그런 일을 한다면,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");
}

인것 같습니다intrinsicContentSize텍스트 세트가 있는 레이블에 대한 작업을 수행합니다.attributedText그리고.text그런 점을 염두에 두고 모든 경계 상자의 부기를 안전하게 제거하고 다음과 같이 단순화할 수 있다고 생각합니다.

스위프트 5.x

extension UILabel {
    var isTruncated: Bool {
       frame.width < intrinsicContentSize.width
    }

    var isClipped: Bool {
        frame.height < intrinsicContentSize.height
    }
}

스위프트 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 {
        guard numberOfLines > 0 else { return false }
        return countLabelLines() > numberOfLines
    }
}

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

iDev의 답변에 추가하려면 다음을 사용해야 합니다.intrinsicContentSizeframe.

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

이 범주를 사용하여 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

이게 그거다.이 기능은 다음과 같이 작동합니다.attributedText평원으로 돌아가기 전에.text여러 글꼴 패밀리, 크기 및 NSText Attachment를 다루는 사람들에게 매우 적합합니다!

작동하지만, 할 수 있습니다.isTruncated그렇지 않으면 레이블 자체가 레이아웃 방법을 알지 못하기 때문에 레이블이 잘렸는지 여부조차 알 수 없습니다.

를 그냥 가 없습니다.NSString그리고.sizeThatFits를 얻었는지 요. BTW는 번 했듯이 나는사람들결긍얻확수과없신었다할지이. BTW, 여번언듯했.sizeThatFits그것이 고려되기 때문에 전혀 이상적이지 않습니다.numberOfLines우리가 하려는 것의 전체 목적을 무너뜨리는 결과적인 크기에 대해, 왜냐하면.isTruncated 언나돌곤했습니다오아제했다▁always▁return를 반환합니다.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
    }
}

스위프트 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
    }
}

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

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

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

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

자동 레이아웃(최대 높이 설정) 및 속성 텍스트를 사용할 때 문제가 발생했습니다.

줄 사이의 간격이 무시되었습니다(전달된 경우에도).attributes에▁boundingRectmethod될 수 .

제가 찾은 해결책은 다음과 같습니다.

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

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

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
    }

}

스위프트 5

세 줄만 표시하도록 설정된 다중 줄 UI 레이블의 예입니다.

    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 

    }
}

Swift 5.x에서

let size = label.text?.size(withAttributes: [NSAttributedString.Key.font: label.font!])
if size!.width > label.bounds.size.width {
    debugPrint("Size increased", size?.width ?? 0, label.bounds.size.width, label.text ?? "")
}

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

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

용사를 합니다.numberOfLines0일 수 있고 높이 제약으로 인해 레이블이 잘릴 수 있기 때문에 항상 유용한 것은 아닙니다.또한.intrinsicContentSize제 경우에는 정확한 사이즈를 반환하지 않았습니다.다음 확장을 사용할 수 있습니다.

extension UILabel {

    var currentContentSize: CGSize {
      layoutIfNeeded()
      let myText = text! as NSString
      let attributes: [NSAttributedString.Key: Any] = [.font: font!]

      let labelRect = myText.boundingRect(with: CGSize(width: bounds.width,
                                                       height: .greatestFiniteMagnitude),
                                          options: .usesLineFragmentOrigin,
                                          attributes: attributes,
                                          context: nil)
      return CGSize(width: labelRect.width, height: labelRect.height)
    }

    var isTruncated: Bool {
      layoutIfNeeded()
      return frame.width < currentContentSize.width || frame.height < currentContentSize.height
    }
}

iOS 6(네, 일부는 여전히 처리해야 합니다)을 처리하기 위해 @iDev의 답변에 대한 또 다른 확장이 있습니다.iOS 6의 경우 호출 크기 전에 UI 레이블의 줄 수가 0으로 설정되어 있는지 확인하는 것이 중요합니다.적합합니다. 적합하지 않은 경우 레이블 텍스트를 그리는 데 "높이만큼 선 수를 그릴 점"이 필요하다는 결과가 표시됩니다.

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

스위프트 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
        }
    }
}

레이블의 제목 속성을 설정하는 것이 쉽지 않을까요? 이 설정을 하면 호핑 시 전체 레이블이 표시됩니다.

라벨의 길이와 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());
}

언급URL : https://stackoverflow.com/questions/3077109/how-to-check-if-uilabel-is-truncated

반응형