iOS7 TextKit: bullet point alignment iOS7 TextKit: bullet point alignment ios ios

iOS7 TextKit: bullet point alignment


So I've looked around, and here is the extracted minimal code from Duncan's answer to make it work:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:yourLabel.text];NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];[paragrahStyle setParagraphSpacing:4];[paragrahStyle setParagraphSpacingBefore:3];[paragrahStyle setFirstLineHeadIndent:0.0f];  // First line is the one with bullet point[paragrahStyle setHeadIndent:10.5f];    // Set the indent for given bullet character and size font[attributedString addAttribute:NSParagraphStyleAttributeName value:paragrahStyle                         range:NSMakeRange(0, [self.descriptionLabel.text length])];yourLabel.attributedText = attributedString;

And here is the result of that in my app:

Quadratic Master


Below it the code I use to set a bulleted paragraph. This comes straight out of a working app and is used to apply the style to the entire paragraph in response to a user clicking on a formatting button. I have tried to put in all the dependent methods but may have missed some.

Note that I am setting most indents in centimetres and hence the use of the conversion functions at the end of the listing.

I am also checking for the presence of a tab character (no tab key on iOS!) and automatically insert a dash and a tab.

If all you need is the paragraph style then look at the last few methods below where the firstLineIndent etc get set up.

Note that these calls all get wrapped in [textStorage beginEditing/endEditing]. Despite the (IBAction) below the method is not getting called by a UI object directly.

        - (IBAction) styleBullet1:(id)sender        {            NSRange charRange = [self rangeForUserParagraphAttributeChange];            NSTextStorage *myTextStorage = [self textStorage];            // Check for "-\t" at beginning of string and add if not found            NSAttributedString *attrString = [myTextStorage attributedSubstringFromRange:charRange];            NSString *string = [attrString string];            if ([string rangeOfString:@"\t"].location == NSNotFound) {                NSLog(@"string does not contain tab so insert one");                NSAttributedString * aStr = [[NSAttributedString alloc] initWithString:@"-\t"];                // Insert a bullet and tab                [[self textStorage] insertAttributedString:aStr atIndex:charRange.location];            } else {                NSLog(@"string contains tab");            }            if ([self isEditable] && charRange.location != NSNotFound)            {                [myTextStorage setAttributes:[self bullet1Style] range:charRange];            }        }        - (NSDictionary*)bullet1Style        {            return [self createStyle:[self getBullet1ParagraphStyle] font:[self normalFont] fontColor:[UIColor blackColor] underlineStyle:NSUnderlineStyleNone];        }        - (NSDictionary*)createStyle:(NSParagraphStyle*)paraStyle font:(UIFont*)font fontColor:(UIColor*)color underlineStyle:(int)underlineStyle        {            NSMutableDictionary *style = [[NSMutableDictionary alloc] init];            [style setValue:paraStyle forKey:NSParagraphStyleAttributeName];            [style setValue:font forKey:NSFontAttributeName];            [style setValue:color forKey:NSForegroundColorAttributeName];            [style setValue:[NSNumber numberWithInt: underlineStyle] forKey:NSUnderlineStyleAttributeName];            FLOG(@" font is %@", font);            return style;        }        - (NSParagraphStyle*)getBullet1ParagraphStyle        {            NSMutableParagraphStyle *para;            para = [self getDefaultParagraphStyle];            NSMutableArray *tabs = [[NSMutableArray alloc] init];            [tabs addObject:[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:[self ptsFromCMF:1.0] options:nil]];            //[tabs addObject:[[NSTextTab alloc] initWithType:NSLeftTabStopType location:[self ptsFromCMF:1.0]]];            [para setTabStops:tabs];            [para setDefaultTabInterval:[self ptsFromCMF:2.0]];            [para setFirstLineHeadIndent:[self ptsFromCMF:0.0]];            //[para setHeaderLevel:0];            [para setHeadIndent:[self ptsFromCMF:1.0]];            [para setParagraphSpacing:3];            [para setParagraphSpacingBefore:3];            return para;        }    - (NSMutableParagraphStyle*)getDefaultParagraphStyle    {        NSMutableParagraphStyle *para;        para = [[NSParagraphStyle defaultParagraphStyle]mutableCopy];        [para setTabStops:nil];        [para setAlignment:NSTextAlignmentLeft];        [para setBaseWritingDirection:NSWritingDirectionLeftToRight];        [para setDefaultTabInterval:[self ptsFromCMF:3.0]];        [para setFirstLineHeadIndent:0];        //[para setHeaderLevel:0];        [para setHeadIndent:0.0];        [para setHyphenationFactor:0.0];        [para setLineBreakMode:NSLineBreakByWordWrapping];        [para setLineHeightMultiple:1.0];        [para setLineSpacing:0.0];        [para setMaximumLineHeight:0];        [para setMinimumLineHeight:0];        [para setParagraphSpacing:6];        [para setParagraphSpacingBefore:3];        //[para setTabStops:<#(NSArray *)#>];        [para setTailIndent:0.0];        return para;    }-(NSNumber*)ptsFromCMN:(float)cm{    return [NSNumber numberWithFloat:[self ptsFromCMF:cm]];}-(float)ptsFromCMF:(float)cm{    return cm * 28.3464567;}


This is the easiest solution I've found:

let bulletList = UILabel()let bulletListArray = ["line 1 - enter a bunch of lorem ipsum here so it wraps to the next line", "line 2", "line 3"]let joiner = "\n"var paragraphStyle = NSMutableParagraphStyle()paragraphStyle.headIndent = 10paragraphStyle.firstLineHeadIndent = 0let attributes = [NSParagraphStyleAttributeName: paragraphStyle]let bulletListString = joiner.join(bulletListArray.map { "• \($0)" })bulletList.attributedText = NSAttributedString(string: bulletListString, attributes: attributes)

the theory being each string in the array acts like a 'paragraph' and the paragraph style gets 0 indent on the first line which gets a bullet added using the map method.. then for every line after it gets a 10 px indent (adjust spacing for your font metrics)