Как проверить, урезан ли UILabel? - PullRequest
88 голосов
/ 20 июня 2010

У меня есть UILabel, который может иметь различную длину в зависимости от того, работает ли мое приложение в портретном или альбомном режиме на iPhone или iPad. Когда текст слишком длинный, чтобы отображаться в одной строке, и он усекается, я хочу, чтобы пользователь мог нажать на него и получить всплывающее окно с полным текстом.

Как проверить, усекает ли UILabel текст? Это вообще возможно? Прямо сейчас я просто проверяю разные длины в зависимости от того, в каком режиме я нахожусь, но он работает не очень хорошо.

Ответы [ 18 ]

1 голос
/ 04 июня 2018

У меня были проблемы с 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
    }
}
1 голос
/ 09 мая 2018

Вот выбранный ответ в Swift 3 (как расширение). ОП спрашивал о метках в 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
    }
}
1 голос
/ 14 мая 2018
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 голос
/ 09 октября 2014

Чтобы добавить к тому, что @ 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;
}
0 голосов
/ 23 апреля 2014

Поскольку во всех приведенных выше ответах используются устаревшие методы, я подумал, что это может быть полезно:

- (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 голосов
/ 26 января 2017

раствор 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
        }
    }
}
0 голосов
/ 04 февраля 2016

Не было бы легко установить атрибут заголовка для метки, при установке этого параметра при наведении будет отображаться полная метка.

Вы можете рассчитать длину метки и ширину div (преобразовать в длину - jQuery / Javascript - Как преобразовать значение пикселя (20 пикселей) в числовое значение (20) ).

установить jquery для установки заголовка, если длина больше ширины div.

var divlen = parseInt(jQuery("#yourdivid").width,10);
var lablen =jQuery("#yourlabelid").text().length;
if(lablen < divlen){
jQuery("#yourlabelid").attr("title",jQuery("#yourlabelid").text());
}
0 голосов
/ 30 марта 2015

Чтобы справиться с iOS 6 (да, некоторые из нас все еще должны), вот еще одно дополнение к ответу @ iDev. Ключевой вывод заключается в том, что для iOS 6 перед вызовом sizeThatFits убедитесь, что для numberOfLines вашей UILabel установлено значение 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);
}
...