How can I use NSParagraphStyle to create a bulleted list in UITextView?

131 views Asked by At

I'm trying to support bulleted list formatting in a UITextView in my app. I've googled around and found various answers to questions (like here) that suggest using NSParagraphStyle. Right now to make a given line bullet-formatted, I'm prepending a bullet (Unicode 2022) plus a tab (•\t) and applying a paragraph style to the line generated like this, given an indent level >= 1:

func makeBulletStyle(forLevel indentLevel: Int) -> NSParagraphStyle {
    let indentInterval = 15;
    let result = NSMutableParagraphStyle()
    
    //Indent the first line of this paragraph for its indent level
    result.firstLineHeadIndent = CGFloat(indentLevel * indentInterval)
    
    let tab = NSTextTab(textAlignment: .left, location: CGFloat(indentInterval))
    result.tabStops = [tab]
    
    result.defaultTabInterval = CGFloat(indentInterval)
    
    //Indent wrapped lines in this paragraph so they line up under the first line,
    //which is indented and then tabbed. Basically firstLineHeadIndent + indentInterval
    result.headIndent = CGFloat((indentLevel + 1) * indentInterval)
    
    return result
}

This appears to work if I always use the same bullet character for the line prefix. But if I switch to using different characters for different levels, like most format-capable text editors do - empty circles, triangles, etc - then the indent and tab distances get wonky, and things don't line up anymore.

These two screenshots only change the tab characters:

Desired spacing

Wonky spacing with different bullet characters

What am I doing wrong here? Why do different tab characters cause issues? Right now I'm working under the admittedly shaky assumptions that:

I also don't quite know what role the indent interval plays here, but if I don't set it then the text on each list item ends up on the line after the bullet itself.

1

There are 1 answers

0
Nicola D'Aniello On

If you look at the NSSParagraphStyle documentation you’ll see it supports lists by use of the textLists attribute.

It also supports different list types and nested lists natively, all you need to do is add them to the property list.

Most answers you’ll find on stackoverflow about UITextView are outdated. Your best bet is to carefully read the Apple docs and watch the WWDC videos.