How to check if UILabel has attributedText or normal text programmatically?
Asked Answered
D

5

10

Is there any way to tell if UILabel has its text set using label.attributedText or label.text property?

The problem is when you set attributedText, text is also updated and vice versa, so it is not possible to check these properties for nil.

Driskill answered 3/4, 2015 at 18:41 Comment(2)
what are you trying to accomplish from figuring this out?Usage
Please indicate that you mean to check programmatically if a label has attributedText (if this is in fact what you mean).Orest
D
0

This is what I use. If range length equals the unattributed text length then the text only has a single attribute and is therefore unattributed.

NSRange range;
[label.attributedText attributesAtIndex:0 effectiveRange:&range];
BOOL isAttributed = label.text.length==range.length;
Dive answered 29/8, 2017 at 16:15 Comment(2)
I think the last line should be BOOL isAttributed = label.text.length!=range.length.Crenelate
This will crash if the attributedText.string length is 0 (At least when I ported it to swift). I will post an updated answer with my implementation below.Stoplight
R
7

Inspired by @lukas-o I have written an extension on UILabel that determines if it contains an attributedText or not. In fact if the NSAttributedString does not contain any attributes, this computed property will evaluate it to not be attributed.

extension UILabel {
    var isAttributed: Bool {
        guard let attributedText = attributedText else { return false }
        let range = NSMakeRange(0, attributedText.length)
        var allAttributes = [Dictionary<String, Any>]()
        attributedText.enumerateAttributes(in: range, options: []) { attributes, _, _ in
            allAttributes.append(attributes)
        }
        return allAttributes.count > 1
    }
} 
Raynold answered 23/4, 2017 at 11:7 Comment(1)
Looking at my own answer 2 years after I wrote it... Why did I put > 1 instead of > 0 (or just use return !allAttributes.isEmpty)? You as a reader can test isEmpty, sorry for the confusionRaynold
M
2

From the apple docs:

This property is nil by default. Assigning a new value to this property also replaces the value of the text property with the same string data, albeit without any formatting information. In addition, assigning a new a value updates the values in the font, textColor, and other style-related properties so that they reflect the style information starting at location 0 in the attributed string.

You are right, it's not possible to find that out checking one or the other for nil. One way you could know that the text is attributed would be to use something like:

NSMutableArray *strAttrs = [NSMutableArray new];
NSMutableArray *strRanges = [NSMutableArray new];

[label.attributedText enumerateAttributesInRange:NSMakeRange(0, label.attributedText.length) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
        [strAttrs addObject:attrs];
        [strRanges addObject:[NSValue valueWithRange:(range)]];
}];

This way you could get see whether more than one attribute is there. You could also compare the attributes whether they match your standard attributes and assume that the text property has been set only in this case.

Millardmillboard answered 12/5, 2015 at 15:24 Comment(0)
D
0

This is what I use. If range length equals the unattributed text length then the text only has a single attribute and is therefore unattributed.

NSRange range;
[label.attributedText attributesAtIndex:0 effectiveRange:&range];
BOOL isAttributed = label.text.length==range.length;
Dive answered 29/8, 2017 at 16:15 Comment(2)
I think the last line should be BOOL isAttributed = label.text.length!=range.length.Crenelate
This will crash if the attributedText.string length is 0 (At least when I ported it to swift). I will post an updated answer with my implementation below.Stoplight
S
0

Here is the implementation I came up with, with some slightly altered logic. It is a Swift port of @Vallette 's accepted answer, with additional guard statements.

The function will only return true if the attributedText is not nil, not empty, and has at least one attribute that does not apply across the entire range of the text:

extension UILabel {

    var isPartiallyAttributed: Bool {
        guard let attributedText = attributedText else {
            return false
        }
        guard !attributedText.string.isEmpty else {
            return false
        }
        var range = NSRange()
        attributedText.attributes(at: 0, effectiveRange: &range)
        return attributedText.string.count != range.length
    }
}
Stoplight answered 28/6, 2019 at 17:59 Comment(0)
L
0

The better way would be to check if Range length of attributes are the same as length of the string. If it's the same you can assume this is non-attributed label. However, i don't know 100% reliable way to check for attributed text if NSAttributes are applied to the whole UILabel text.

private extension UILabel {
    
    var hasAttributedText: Bool {
    guard let attributedText = attributedText,
          attributedText.string.isEmpty == false else { return false }
    var range = NSRange(location: 0, length: attributedText.length)
    _ = attributedText.attributes(at: 0,
                                  effectiveRange: &range)
    return range.length != attributedText.length
}
    
}
Labourer answered 26/10, 2020 at 17:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.