NSAttributedString如何插入圆点?

34

我有一个NSAttributedString,我想在文字的开头插入一个圆点符号。我该怎么做?如何创建一个CTParagraphStyle,以便在显示文本时创建这个圆点符号?

编辑: 应该在iOS上可用。

7个回答

43

这里是一个更现代的方法,适用于 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])];

太棒了,非常感谢。已确认在iOS 9.3上运行正常。 - Robert Atkins

40

这里有一个使用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)

添加项目符号属性

适用于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
}

这是结果:

在此输入图片描述


这段文字涉及IT技术,它展示了一个图片链接。

1
这是一个很好的回答,但如果字符串包含换行符(“\n”),那么缩进就会出现问题。我该如何处理这种情况? - PrepareFor

36

简单的部分:[mutableAttributedString insertAttributedString: @"•\t" atIndex:0];

难一些的部分。类似以下内容(这是从一个大项目中提取出来的,但可能会给你一个不错的开端)。

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

您需要包含CoreText框架,然后导入CoreText/CoreText.h


这是在iOS中设置段落样式的示例,但我建议在使用它们的属性字符串发布之前,不要释放“tabStops”和“style”。在我的项目中,我不得不对所有拥有的样式组件进行适当处理,以避免出现EXC_BAD_ACCESS错误。 - Wienke

5

这里是Krunal在Objective-C中的优秀回答。它还移除了最后一个项目的段落间距,以避免UILabel底部出现额外的填充。

UILabel *label = [UILabel new];
label.frame = CGRectMake(40, 100, 280, 600);
label.textColor = UIColor.lightGrayColor;
label.numberOfLines = 0;

NSArray *stringArray = @[@"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 = [self attributedStringForBulletTexts:stringArray
                                                   withFont:label.font
                                               bulletString:@""
                                                indentation:20
                                                lineSpacing:2
                                           paragraphSpacing:12
                                                  textColor:UIColor.grayColor
                                                bulletColor:UIColor.greenColor];

以下是创建实际属性文本的函数:

- (NSAttributedString *)attributedStringForBulletTexts:(NSArray *)stringList
                                              withFont:(UIFont *)font
                                          bulletString:(NSString *)bullet
                                           indentation:(CGFloat)indentation
                                           lineSpacing:(CGFloat)lineSpacing
                                      paragraphSpacing:(CGFloat)paragraphSpacing
                                             textColor:(UIColor *)textColor
                                           bulletColor:(UIColor *)bulletColor {

    NSDictionary *textAttributes = @{NSFontAttributeName: font,
                                 NSForegroundColorAttributeName: textColor};
    NSDictionary *bulletAttributes = @{NSFontAttributeName: font, NSForegroundColorAttributeName: bulletColor};

    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    paragraphStyle.tabStops = @[[[NSTextTab alloc] initWithTextAlignment: NSTextAlignmentLeft location:indentation options:@{}]];
    paragraphStyle.defaultTabInterval = indentation;
    paragraphStyle.lineSpacing = lineSpacing;
    paragraphStyle.paragraphSpacing = paragraphSpacing;
    paragraphStyle.headIndent = indentation;

    NSMutableAttributedString *bulletList = [NSMutableAttributedString new];

    for (NSString *string in stringList) {
        NSString *formattedString = [NSString stringWithFormat:@"%@\t%@\n", bullet, string];
        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:formattedString];
        if ([string isEqualToString: stringList.lastObject]) {
            paragraphStyle = [paragraphStyle mutableCopy];
            paragraphStyle.paragraphSpacing = 0;
        }
        [attributedString addAttributes:@{NSParagraphStyleAttributeName: paragraphStyle} range:NSMakeRange(0, attributedString.length)];
        [attributedString addAttributes:textAttributes range:NSMakeRange(0, attributedString.length)];

        NSRange rangeForBullet = [formattedString rangeOfString:bullet];
        [attributedString addAttributes:bulletAttributes range:rangeForBullet];
        [bulletList appendAttributedString:attributedString];
    }

    return bulletList;
}

5
你不能在iOS中使用段落样式来实现带有项目符号的列表。请按照需要设置制表位,然后在段落开头插入一个制表符、项目符号和制表符。
CTParagraphStyle相当不灵活,所以你不能随意添加新样式。但是你可以在NSAttributedString中的任意运行中添加任何属性(MYBulletStyle)。这对于在打包NSAttributedString时传递项目符号列表信息并在准备显示时重新构建字符串以包括项目符号非常有用。但Core Text不会自动呈现项目符号。

1
我知道这篇文章很旧了,但你介意给一些样例吗?当你想要整个段落缩进除了项目符号时,如何使用制表位解决问题? - aryaxt
我知道这个问题很老了,但是...将段落缩进和制表位设置为相同的值。但是你要将第一行段落缩进设置为无。然后第一行以符号和制表位开头。结果是在符号后的第一行文本与其余文本对齐。 - Nick Moore

3

虽然这并不是针对此问题的实际答案,但这可以帮助。

只需添加"•"

我也在寻找类似于我的textView的东西。我所做的就是将上述字符串附加到我的字符串中,并将其传递给我的textView,标签也可以采用同样的方法。我回答这个问题是为了未来的查阅者。


嗯,我在想当你增加字体时,它是否能够适当地调整大小。 - aryaxt
如果你认为这是一种很酷的方式,就点赞吧。 - Zac24

1
另一种对@krunal答案的改进,这次稍微简化了一下,作为Swift 5中NSAttributedString的初始化器:
extension NSAttributedString {
    convenience init(stringList: [String], bullet: String = "\u{2022}", indentation: CGFloat = .zero, lineSpacing: CGFloat = .zero, paragraphSpacing: CGFloat = .zero) {
        let paragraphStyle = NSMutableParagraphStyle()
        let tabStopOptions: [NSTextTab.OptionKey: Any] = [:]
        
        paragraphStyle.tabStops = [
            NSTextTab(textAlignment: .left, location: indentation, options: tabStopOptions)
        ]
        
        paragraphStyle.defaultTabInterval = indentation
        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)
            let attributedStringRange = NSMakeRange(0, attributedString.length)
            attributedString.addAttributes([NSAttributedString.Key.paragraphStyle : paragraphStyle], range: attributedStringRange)
            
            bulletList.append(attributedString)
        }
        
        self.init(attributedString: bulletList)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接