Search code examples
iosuilabelnsattributedstring

NSAttributedString displayed in UILabel wrong on iOS14


An NSMutableAttributedString with some attributes was correctly displayed in an UILabel up until iOS 12, but is wrong/different on iOS 14:

The string "bukskin" has two letters coloured red, the last 4 letters are underlined, correctly on iOS 12:

enter image description here

On iOS 14 the underlining extends beyond the end of the word for about two letters. This seems to only happen if the underlining is at the END of the string:

enter image description here

Dumps of the string attributes for iOS 12 and iOS 14 look identical, yet the string is displayed differently on screen in an UILabel, on iOS 14. Am I missing something?

Dump for iOS 12 (using enumerateAttributesInRange):

word=bukskin attributed_word=b{
    NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
    NSLigature = 0;
    NSUnderline = 0;
}uk{
    NSColor = "UIExtendedGrayColorSpace 0 1";
    NSLigature = 0;
    NSUnderline = 0;
}s{
    NSColor = "UIExtendedGrayColorSpace 0 1";
    NSLigature = 0;
    NSUnderline = 1;
}k{
    NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
    NSLigature = 0;
    NSUnderline = 1;
}in{
    NSColor = "UIExtendedGrayColorSpace 0 1";
    NSLigature = 0;
    NSUnderline = 1;
} attrs={
    NSColor = "UIExtendedGrayColorSpace 0 1";
    NSLigature = 0;
    NSUnderline = 1;
}

Dump for iOS14:

word=bukskin attributed_word=b{
    NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
    NSLigature = 0;
    NSUnderline = 0;
}uk{
    NSColor = "<UIDynamicSystemColor: 0x600003682440; name = labelColor>";
    NSLigature = 0;
    NSUnderline = 0;
}s{
    NSColor = "<UIDynamicSystemColor: 0x600003682440; name = labelColor>";
    NSLigature = 0;
    NSUnderline = 1;
}k{
    NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
    NSLigature = 0;
    NSUnderline = 1;
}in{
    NSColor = "<UIDynamicSystemColor: 0x600003682440; name = labelColor>";
    NSLigature = 0;
    NSUnderline = 1;
} attrs={
    NSColor = "<UIDynamicSystemColor: 0x600003682440; name = labelColor>";
    NSLigature = 0;
    NSUnderline = 1;
}

Solution

  • The link in Tarun Tyagi's comment hints at a fix: setting the baseline offset to 0 for the entire attributed string. That seems to work. Right after initialising I now do:

    [att_word addAttribute:NSBaselineOffsetAttributeName value:[NSNumber numberWithInt:0] range:NSMakeRange(0, att_word.length)];
    

    I'll file a bug with Apple.

    The attributes dump now is:

    word=bukskin attributed_word=b{
        NSBaselineOffset = 0;
        NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
        NSLigature = 0;
        NSUnderline = 0;
    }uk{
        NSBaselineOffset = 0;
        NSColor = "<UIDynamicSystemColor: 0x600000506f00; name = labelColor>";
        NSLigature = 0;
        NSUnderline = 0;
    }s{
        NSBaselineOffset = 0;
        NSColor = "<UIDynamicSystemColor: 0x600000506f00; name = labelColor>";
        NSLigature = 0;
        NSUnderline = 1;
    }k{
        NSBaselineOffset = 0;
        NSColor = "UIExtendedSRGBColorSpace 0.8125 0 0 1";
        NSLigature = 0;
        NSUnderline = 1;
    }in{
        NSBaselineOffset = 0;
        NSColor = "<UIDynamicSystemColor: 0x600000506f00; name = labelColor>";
        NSLigature = 0;
        NSUnderline = 1;
    } attrs={
        NSBaselineOffset = 0;
        NSColor = "<UIDynamicSystemColor: 0x600000506f00; name = labelColor>";
        NSLigature = 0;
        NSUnderline = 1;
    }