Search code examples
iosuilabeltruncate

How can I standardize the the varying truncating dot characters of UILabel?


I have a plist file which I decode to load data onto my application. This plist file contains String type values that gets mapped to UILabel's text property.

I noticed that the truncating behavior of the text in the label is not always the same. To be more specific, the three dots that are added when the text is truncated are, as opposed to my expectation, two kinds: one being ... and the other being ⋯ which appears to be this unicode character in this link.

I checked UILabel's attribute settings but I was unable to find any settings related to this behavior.

Has anyone else experienced this problem and standardized the truncating character to be ...?

Here is the image describing the problem mentioned above. Both labels have 2 lines and have new line escape character inserted between the first line and the second line of text. I am posting a link to this image because apparently I don't have enough reputation to post an image.

varying truncating characters of UILabel


Solution

  • IMO this is a bug in UILabel, and it may be worth opening a Feedback about it.

    TL;DR: I recommend using TTTAttributedLabel.


    Long-winded answer, because this was such an interesting question:

    UILabel uses a different ellipsis based on the language script being truncated. As you've noticed, for most scripts, they use HORIZONTAL ELLIPSIS (), or something very similar. But for Chinese, Japanese, and Korean (CJK), they use MIDLINE HORIZONTAL ELLIPSIS (), or again, something very similar. The only other exception I've found is Burmese, which uses three circles that I don't recognize.

    In my tests, all the following used : Latin, Cyrillic, Bengali, Arabic, Hebrew, Hindi, Thai, Kannada, Nepali, and Mongolian (I kid. iOS can't layout Mongolian. Nobody can layout Mongolian, but it still uses ). UILabel even uses for Lao, even though I thought was specifically for that, but I guess eventually everything becomes Latin.

    The problem with UILabel being so clever for CJK and Burmese is that it decides what character to use exclusively by looking at the first character being removed. And it thinks SPACE is Latin (or at least not "special").

    So what to do? My recommendation is probably to use TTTAttributedLabel, since it lets you configure the truncation character, and more importantly, is open source so you can fix it if it's not working the way you want.

    The second option would be to truncate the text by hand using techniques like the one described in How to change truncate characters in UILabel?. There are probably better ways to do it using CTFrameGetVisibleStringRange instead of constantly shrinking the string until it fits, but I don't know if it's worth the effort. (If that path sounds useful, I could probably write up something that does it. It's just probably not worth the trouble.)

    And the final option I know is to replace the SPACE character with an "equivalent" CJK character. The closest I've found that works is HANGUL FILLER (U+3164), but I don't like it. It's too wide, and I expect that it will make Korean uncomfortable to read (but I rarely try to read Korean, so I may be wrong here):

    With SPACE: 안녕 하세요

    With FILLER: 안녕ㅤ하세요

    There's also HALFWIDTH HANGUL FILLER (U+FFA0), which is better, but UILabel seems to make it zero width (this may be a font issue, so maybe worth trying):

    With SPACE: 안녕 하세요

    With HALF: 안녕ᅠ하세요

    let string = "안녕 하세요"
    let filler = "\u{3164}"
    label.text = string.replacingOccurrences(of: " ", with: filler)
    

    OTOH, you may run into the same problem if you use any other non-CJK characters, like Latin punctuation or Arabic numerals. So this solution may not scale. And you should make sure that Voice Over properly ignores it.