Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSAttributedString inserting a bullet point?

So I have an NSAttributedString I want to insert a bullet point at the beginning of a portion of text. How can I do this? How do I create a CTPAragraphStyle that creates this bullet point when I display the text?

Edit: Should be available on iOS

like image 203
aryaxt Avatar asked Jul 10 '11 23:07

aryaxt


3 Answers

Here's a more modern approach that works from iOS6:

NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:@"•\texample bullet fill out the text to check what happens on the second line and make sure it is lining up OK"];

NSMutableParagraphStyle *paragraphStyle;
paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setTabStops:@[[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:15 options:nil]]];
[paragraphStyle setDefaultTabInterval:15];
[paragraphStyle setFirstLineHeadIndent:0];
[paragraphStyle setHeadIndent:15];

[string addAttributes:@{NSParagraphStyleAttributeName: paragraphStyle} range:NSMakeRange(0,[string length])];
like image 190
Tijn Avatar answered Nov 10 '22 21:11

Tijn


The easy bit: [mutableAttributedString insertAttributedString: @"•\t" atIndex:0];

The hard bit. Something along the following lines. (This is extracted from a bigger project, but it may give you a decent start.)

NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:@"•\texample bullet fill out the text to check what happens on the second line and make sure it is lining up OK"];

CTTextAlignment alignment = kCTLeftTextAlignment;
CGFloat paragraphSpacing = 0.0;
CGFloat paragraphSpacingBefore = 0.0;
CGFloat firstLineHeadIndent = 15.0;
CGFloat headIndent = 30.0;

CGFloat firstTabStop = 15.0; // width of your indent
CGFloat lineSpacing = 0.45;

CTTextTabRef tabArray[] = { CTTextTabCreate(0, firstTabStop, NULL) };

CFArrayRef tabStops = CFArrayCreate( kCFAllocatorDefault, (const void**) tabArray, 1, &kCFTypeArrayCallBacks );
CFRelease(tabArray[0]);

CTParagraphStyleSetting altSettings[] = 
{
    { kCTParagraphStyleSpecifierLineSpacing, sizeof(CGFloat), &lineSpacing},
    { kCTParagraphStyleSpecifierAlignment, sizeof(CTTextAlignment), &alignment},
    { kCTParagraphStyleSpecifierFirstLineHeadIndent, sizeof(CGFloat), &firstLineHeadIndent},
    { kCTParagraphStyleSpecifierHeadIndent, sizeof(CGFloat), &headIndent},
    { kCTParagraphStyleSpecifierTabStops, sizeof(CFArrayRef), &tabStops},
    { kCTParagraphStyleSpecifierParagraphSpacing, sizeof(CGFloat), &paragraphSpacing},
    { kCTParagraphStyleSpecifierParagraphSpacingBefore, sizeof(CGFloat), &paragraphSpacingBefore}
}; 

CTParagraphStyleRef style;
style = CTParagraphStyleCreate( altSettings, sizeof(altSettings) / sizeof(CTParagraphStyleSetting) );

if ( style == NULL )
{
    NSLog(@"*** Unable To Create CTParagraphStyle in apply paragraph formatting" );
    return;
}

[string addAttributes:[NSDictionary dictionaryWithObjectsAndKeys:(NSObject*)style,(NSString*) kCTParagraphStyleAttributeName, nil] range:NSMakeRange(0,[string length])];

CFRelease(tabStops);
CFRelease(style);

You need to include the CoreText framework and then import CoreText/CoreText.h

like image 30
Obliquely Avatar answered Nov 10 '22 21:11

Obliquely


Here is nice solution with Swift

let label = UILabel()
label.frame = CGRect(x: 40, y: 100, width: 280, height: 600)
label.textColor = UIColor.lightGray
label.numberOfLines = 0

let arrayString = [
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
    "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
    "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
    "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
]

label.attributedText = add(stringList: arrayString, font: label.font, bullet: "")

self.view.addSubview(label)

Add bullet attributes

Swift 4.2++

func add(stringList: [String],
         font: UIFont,
         bullet: String = "\u{2022}",
         indentation: CGFloat = 20,
         lineSpacing: CGFloat = 2,
         paragraphSpacing: CGFloat = 12,
         textColor: UIColor = .gray,
         bulletColor: UIColor = .green) -> NSAttributedString {

    let textAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor]
    let bulletAttributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: bulletColor]

    let paragraphStyle = NSMutableParagraphStyle()
    let nonOptions = [NSTextTab.OptionKey: Any]()
    paragraphStyle.tabStops = [
        NSTextTab(textAlignment: .left, location: indentation, options: nonOptions)]
    paragraphStyle.defaultTabInterval = indentation
    //paragraphStyle.firstLineHeadIndent = 0
    //paragraphStyle.headIndent = 20
    //paragraphStyle.tailIndent = 1
    paragraphStyle.lineSpacing = lineSpacing
    paragraphStyle.paragraphSpacing = paragraphSpacing
    paragraphStyle.headIndent = indentation

    let bulletList = NSMutableAttributedString()
    for string in stringList {
        let formattedString = "\(bullet)\t\(string)\n"
        let attributedString = NSMutableAttributedString(string: formattedString)

        attributedString.addAttributes(
            [NSAttributedString.Key.paragraphStyle : paragraphStyle],
            range: NSMakeRange(0, attributedString.length))

        attributedString.addAttributes(
            textAttributes,
            range: NSMakeRange(0, attributedString.length))

        let string:NSString = NSString(string: formattedString)
        let rangeForBullet:NSRange = string.range(of: bullet)
        attributedString.addAttributes(bulletAttributes, range: rangeForBullet)
        bulletList.append(attributedString)
    }

    return bulletList
}

Swift 4.0 & 4.1

func add(stringList: [String],
         font: UIFont,
         bullet: String = "\u{2022}",
         indentation: CGFloat = 20,
         lineSpacing: CGFloat = 2,
         paragraphSpacing: CGFloat = 12,
         textColor: UIColor = .gray,
         bulletColor: UIColor = .green) -> NSAttributedString {

    let textAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: textColor]
    let bulletAttributes: [NSAttributedStringKey: Any] = [NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: bulletColor]

    let paragraphStyle = NSMutableParagraphStyle()
    let nonOptions = [NSTextTab.OptionKey: Any]()
    paragraphStyle.tabStops = [
        NSTextTab(textAlignment: .left, location: indentation, options: nonOptions)]
    paragraphStyle.defaultTabInterval = indentation
    //paragraphStyle.firstLineHeadIndent = 0
    //paragraphStyle.headIndent = 20
    //paragraphStyle.tailIndent = 1
    paragraphStyle.lineSpacing = lineSpacing
    paragraphStyle.paragraphSpacing = paragraphSpacing
    paragraphStyle.headIndent = indentation

    let bulletList = NSMutableAttributedString()
    for string in stringList {
        let formattedString = "\(bullet)\t\(string)\n"
        let attributedString = NSMutableAttributedString(string: formattedString)

        attributedString.addAttributes(
            [NSAttributedStringKey.paragraphStyle : paragraphStyle],
            range: NSMakeRange(0, attributedString.length))

        attributedString.addAttributes(
            textAttributes,
            range: NSMakeRange(0, attributedString.length))

        let string:NSString = NSString(string: formattedString)
        let rangeForBullet:NSRange = string.range(of: bullet)
        attributedString.addAttributes(bulletAttributes, range: rangeForBullet)
        bulletList.append(attributedString)
    }

    return bulletList
}

Here is result:

enter image description here

like image 37
Krunal Avatar answered Nov 10 '22 21:11

Krunal