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:
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)