iPhone/iPad:如何准确使用NSAttributedString?

104

很多人在谈论iPhone/iPad上的富文本,也有很多人知道NSAttributedString

但是如何使用NSAttributedString呢?我搜索了很久,没有找到任何线索。

我知道如何设置一个NSAttributedString,那么如何在iPhone/iPad上显示带富文本的文本呢?

官方文档说它应该与CoreText.Framework一起使用,这是什么意思?

是否有像这样简单的方法呢?

NSAttributedString *str;
.....
UILabel *label;
label.attributedString = str;

Three20看起来是一个非常令人印象深刻的库:https://github.com/facebook/three20 - David H
87
Three20很糟糕。 - bandejapaisa
@bandejapaisa,是的,Three20最糟糕的事情就是它们没有好的文档。 - Jack
4
那很烦人,但我认为还有更糟糕的事情。在过去的6个月里,我一直在维护一个使用Three20的项目……他们对内存的一些处理让我感到困惑。代码非常脆弱,因为它没有按照正统的方式处理内存。最好自己编写所需功能的代码,因为你不太可能需要他们提供的所有功能。自己动手做......你会学到更多知识,而且更有趣,你可能会做得更好! - bandejapaisa
为什么不使用:label.attributedText = str;? - x4h1d
显示剩余2条评论
9个回答

155

从 iOS 6.0 开始,你可以这样做:

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"Hello. That is a test attributed string."];
[str addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:NSMakeRange(3,5)];
[str addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(10,7)];
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Bold" size:20.0] range:NSMakeRange(20, 10)];
label.attributedText = str;

60
iOS开发计划的第一条规则是不要谈论iOS开发计划。 - Jeremy Moyers
5
iOS 开发计划的第二条规则是...请参见第一条规则。 - futureelite7
32
宣称某人违反了保密协议,就是确认所提供的资料确实存在于iOS6中,因此本身就是违反保密协议。你应该写成类似这样的话:“如果不违反保密协议,就无法对[即将发布的版本]中的内容发表评论。” - hatfinch
如果你发现自己经常写大量的属性字符串,请查看这篇文章/类别。它可以让创建变得更容易。http://www.raizlabs.com/dev/2014/03/nsattributedstring-creation-helpers/ - Alex Rouse

81

你应该看一下AliSoftware的OHAttributedLabel。它是UILabel的子类,可以绘制NSAttributedString,并提供方便的方法从UIKit类中设置NSAttributedString的属性。

从存储库中提供的示例:

#import "NSAttributedString+Attributes.h"
#import "OHAttributedLabel.h"

/**(1)** Build the NSAttributedString *******/
NSMutableAttributedString* attrStr = [NSMutableAttributedString attributedStringWithString:@"Hello World!"];
// for those calls we don't specify a range so it affects the whole string
[attrStr setFont:[UIFont systemFontOfSize:12]];
[attrStr setTextColor:[UIColor grayColor]];
// now we only change the color of "Hello"
[attrStr setTextColor:[UIColor redColor] range:NSMakeRange(0,5)];


/**(2)** Affect the NSAttributedString to the OHAttributedLabel *******/
myAttributedLabel.attributedText = attrStr;
// Use the "Justified" alignment
myAttributedLabel.textAlignment = UITextAlignmentJustify;
// "Hello World!" will be displayed in the label, justified, "Hello" in red and " World!" in gray.

注意:在iOS 6及以上版本,您可以使用UILabel的attributedText属性呈现带属性的字符串。


5
它在2010年11月的一次提交中更名为OHAttributedLabel(请参阅https://github.com/AliSoftware/Ali-Cocoa-Classes/commit/b146abd05f314f5de1a829a4163ac0842387d1a9)。我已更新我的答案。 - Wes
1
谢谢Wes!还有编写代码的Olivier Halligon!谢谢! - DenNukem
1
感谢@Wes提到我的类,也感谢@DenNukem给予的认可...我没意识到它这么有名;) 无论如何,自从原始帖子以来,我对这个类进行了许多更新和修复,所以别忘了拉取GitHub仓库! - AliSoftware
你的代码每一行都出现错误。根据文档,你提供的方法在实际类中都不存在,我感到困惑:http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSAttributedString_Class/Reference/Reference.html。 - aryaxt
这并没有真正回答用户的问题。与其解释如何使用属性字符串,不如解释如何使用替代方法。 - Billy Lazzaro
显示剩余7条评论

15
你应该尝试使用TTTAttributedLabel。它是UILabel的即插即用替代品,可与NSAttributedString一起使用,并且对于UITableViewCells具有足够的性能。

这个类可以在下面提到的Three20库中找到。 - David H
10
不,这不是来自于three20(注意三个T字母)。 - vikingosegundo

6

iOS 6中UILabel的文本对齐方式解决方案:使用NSMutableAttributedString并添加NSMutableParagraphStyle属性。类似于以下代码:

NSString *str = @"Hello World!";
NSRange strRange = NSMakeRange(0, str.length);
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:str];

NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];
[paragrahStyle setAlignment:NSTextAlignmentCenter];
[attributedStr addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:strRange];

myUILabel.attributedText = attributedStr;

6
几乎可以。只需使用CATextLayer。它有一个字符串属性,您可以将其设置为NSAttributedString。
编辑(2012年11月):当然,在iOS 6中所有这些都已经改变了。在iOS 6中,您可以直接将属性字符串分配给标签的attributedText。

1
您能否更加具体一些,例如提供一个使用示例? - William Niu
1
是的,它叫做我的书《Programming iOS 5》。这是书中的代码示例:https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch23p689styledText1/p579p593styleText1/StyledText.m - matt

6
我认为给出解析(简化的)HTML字符串以创建NSAttributedString的示例会很有用。
它不是完整的 - 它只处理<b>和<i>标签,而且没有任何错误处理 - 但希望也是一个如何开始使用NSXMLParserDelegate的有用示例...

@interface ExampleHTMLStringToAttributedString : NSObject<NSXMLParserDelegate>

+(NSAttributedString*) getAttributedStringForHTMLText:(NSString*)htmlText WithFontSize:(CGFloat)fontSize;

@end

@interface ExampleHTMLStringToAttributedString()
@property NSString *mpString;
@property NSMutableAttributedString *mpAttributedString;

@property CGFloat mfFontSize;
@property NSMutableString *appendThisString;
@property BOOL mbIsBold;
@property BOOL mbIsItalic;
@end

@implementation ExampleHTMLStringToAttributedString
@synthesize mpString;
@synthesize mfFontSize;
@synthesize mpAttributedString;
@synthesize appendThisString;
@synthesize mbIsBold;
@synthesize mbIsItalic;

//初始化方法,传入需要转换的字符串
- (id)initWithString:(NSString*)inString {
    self = [super init];
    if (self) {
        if ([inString hasPrefix:@""]) {
          mpString = inString;
        } else {
            mpString = [NSString stringWithFormat:@"%@", inString];
        }
        mpAttributedString = [NSMutableAttributedString new];
    }
    return self;
}

//将HTML格式的文本转换为NSAttributedString对象,fontSize为字体大小
+(NSAttributedString*) getAttributedStringForHTMLText:(NSString*)htmlText WithFontSize:(CGFloat)fontSize {

    ExampleHTMLStringToAttributedString *me = [[ExampleHTMLStringToAttributedString alloc] initWithString:htmlText];
    return [me getAttributedStringWithFontSize:fontSize];
}

//开始解析HTML文本
-(NSAttributedString*) getAttributedStringWithFontSize:(CGFloat)fontSize {

    mfFontSize = fontSize;

    // 解析XML
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[mpString dataUsingEncoding:NSUTF8StringEncoding]];
    parser.delegate = self;
    if (![parser parse]) {
        return nil;
    }

    return mpAttributedString;
}

//拼接已经解析好的文本
-(void) appendTheAccumulatedText {
    UIFont *theFont = nil;

    if (mbIsBold && mbIsItalic) {
        // https://dev59.com/TXM_5IYBdhLWcg3waiiJ
        theFont = [UIFont fontWithName:@"Helvetica-BoldOblique" size:mfFontSize];
    } else if (mbIsBold) {
       theFont = [UIFont boldSystemFontOfSize:mfFontSize];
    } else if (mbIsItalic) {
        theFont = [UIFont italicSystemFontOfSize:mfFontSize];
    } else {
        theFont = [UIFont systemFontOfSize:mfFontSize];
    }

    NSAttributedString *appendThisAttributedString =
    [[NSAttributedString alloc]
     initWithString:appendThisString
     attributes:@{NSFontAttributeName : theFont}];

    [mpAttributedString appendAttributedString:appendThisAttributedString];

    [appendThisString setString:@""];
}

#pragma NSXMLParserDelegate delegate

//开始解析XML文档
-(void)parserDidStartDocument:(NSXMLParser *)parser{
    appendThisString = [NSMutableString new];
    mbIsBold = NO;
    mbIsItalic = NO;
}

//解析到开始标签
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if ([elementName isEqualToString:@"body"]){
    } else if ([elementName isEqualToString:@"i"]) {
      [self appendTheAccumulatedText];
        mbIsItalic = YES;
    } else if ([elementName isEqualToString:@"b"]) {
      [self appendTheAccumulatedText];
        mbIsBold = YES;
    }
}

//解析到结束标签
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    if ([elementName isEqualToString:@"body"]){
      [self appendTheAccumulatedText];
    } else if ([elementName isEqualToString:@"i"]) {
      [self appendTheAccumulatedText];
      mbIsItalic = NO;
    } else if ([elementName isEqualToString:@"b"]) {
        [self appendTheAccumulatedText];
        mbIsBold = NO;
    }
}

//解析到文本内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    [appendThisString appendString:string];
}

//解析出错
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
}

@end

使用方法如下:


  self.myTextView.attributedText = [ExampleHTMLStringToAttributedString getAttributedStringForHTMLText:@"这是<b>加粗</b>文本" WithFontSize:self.myTextView.pointSize];

5

从iOS 6.0开始,您可以这样做:另一个示例代码。

NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"This is my test code to test this label style is working or not on the text to show other user"];

[str addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,31)];
[str addAttribute:NSBackgroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(61,10)];

[str addAttribute:NSFontAttributeName value: [UIFont fontWithName:@"Helvetica-Bold" size:13.0] range:NSMakeRange(32, 28)];
[str addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Helvetica-Bold" size:13.0] range:NSMakeRange(65, 20)];

_textLabel.attributedText = str;

2

如果您使用Swift,请使用以下代码:

这将使标题文本变为粗体:Tilt

var title = NSMutableAttributedString(string: "Title Text")

    title.addAttributes([NSFontAttributeName: UIFont(name: "AvenirNext-Bold", size: iCurrentFontSize)!], range: NSMakeRange(0, 4))

    label.attributedText = title

2

我知道有点晚了,但这对其他人可能会有用。

NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:@"string" attributes:@{NSForegroundColorAttributeName:[UIColor blackColor]}];

[self.label setAttributedText:newString];

将所需属性添加到字典中,并将其作为attributes参数传递。

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