iOS - 属性字符串(NSAttributedString)

NSAttributedString使用

NSAttributedString是一个带有属性的字符串,通过该类可以灵活地操作和呈现多种样式的文字数据。这个类的一个最简单的概括就是NSAttributedString管理一个字符串,以及与该字符串中的单个字符或某些范围的字符串相关的属性,具体实现时,NSAttributedString维护了一个NSString,用来保存最原始的字符串,另有一个NSDictionary用来保存各个子串/字符的属性。

NSAttributedString

@interface NSAttributedString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>

@property (readonly, copy) NSString *string;
- (instancetype)initWithString:(NSString *)str;
- (instancetype)initWithString:(NSString *)str attributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attrs;
- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr;

NSMutableAttributedString

@interface NSMutableAttributedString : NSAttributedString
 
//使用字符串替换某一范围的字符
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
//为某一范围内的文字设置多个属性
- (void)setAttributes:( NSDictionary *)attrs range:(NSRange)range;
 
@end
@interface NSMutableAttributedString (NSExtendedMutableAttributedString)

@property (readonly, retain) NSMutableString *mutableString;
 
//为某一范围内的文字添加某个属性
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
//为某一范围内的文字添加多个属性
- (void)addAttributes:(NSDictionary *)attrs range:(NSRange)range;
//移除某一范围内的某个属性
- (void)removeAttribute:(NSString *)name range:(NSRange)range;
//设置属性字符串替换某一范围内的字符
- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(NSAttributedString *)attrString;
//在某个位置插入属性字符串
- (void)insertAttributedString:(NSAttributedString *)attrString atIndex:(NSUInteger)loc;
//拼接一个属性字符串
- (void)appendAttributedString:(NSAttributedString *)attrString;
//删除某一范围内的字符
- (void)deleteCharactersInRange:(NSRange)range;
//设置属性字符串
- (void)setAttributedString:(NSAttributedString *)attrString;
 
//用于编辑属性字符串. 在修改文字属性的开头和结尾要分别调用beginEditing和endEditing方法,这些方法可以在文字属性发生变化时发送消息给事件监听者。
- (void)beginEditing;
- (void)endEditing;
 
@end

常用属性Key

//设置字体, 该属性所对应的值是一个 UIFont 对象。该属性用于改变一段文本的字体。如果不指定该属性,则默认为12-point Helvetica(Neue)。
UIKIT_EXTERN NSString * const NSFontAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设置段落样式,该属性所对应的值是一个 NSParagraphStyle 对象。该属性在一段文本上应用多个属性。如果不指定该属性,则默认为 NSParagraphStyle 的defaultParagraphStyle 方法返回的默认段落属性。
UIKIT_EXTERN NSString * const NSParagraphStyleAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设置文字颜色,该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的字体颜色。如果不指定该属性,则默认为黑色。
UIKIT_EXTERN NSString * const NSForegroundColorAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设置背景颜色,该属性所对应的值是一个 UIColor 对象。该属性用于指定一段文本的背景颜色。如果不指定该属性,则默认无背景色。
UIKIT_EXTERN NSString * const NSBackgroundColorAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设置连体属性,取值为NSNumber 对象(整数),0 表示没有连体字符,1 表示使用默认的连体字符(注意,iOS 不支持值为 2)。
UIKIT_EXTERN NSString * const NSLigatureAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设定字符间距.该属性所对应的值是一个NSNumber对象(整数)。字母紧排指定了用于调整字距的像素点数。字母紧排的效果依赖于字体。值为0表示不使用字母紧排。默认值为0。
UIKIT_EXTERN NSString * const NSKernAttributeName NS_AVAILABLE(10_0, 6_0);
 
//设置删除线
UIKIT_EXTERN NSString * const NSStrikethroughStyleAttributeName NS_AVAILABLE(10_0, 6_0);
 
//下划线样式,该属性所对应的值是一个 NSNumber 对象(整数)。该值指定是否在文字上加上下划线,该值参考“Underline Style Attributes”。默认值是NSUnderlineStyleNone。
UIKIT_EXTERN NSString * const NSUnderlineStyleAttributeName NS_AVAILABLE(10_0, 6_0);
 
//边线颜色, 该属性所对应的值是一个 UIColor 对象。如果该属性不指定(默认),则等同于 NSForegroundColorAttributeName。否则,指定为删除线或下划线颜色。更多细节见“Drawing attributedstrings that are both filled and stroked”。
UIKIT_EXTERN NSString * const NSStrokeColorAttributeName NS_AVAILABLE(10_0, 6_0);
 
//边线宽度,该属性所对应的值是一个 NSNumber 对象(小数)。该值改变描边宽度(相对于字体size 的百分比)。默认为 0,即不改变。正数只改变描边宽度。负数同时改变文字的描边和填充宽度。例如,对于常见的空心字,这个值通常为3.0。
UIKIT_EXTERN NSString * const NSStrokeWidthAttributeName NS_AVAILABLE(10_0, 6_0);
 
//阴影属性该属性所对应的值是一个 NSShadow 对象。默认为 nil。
UIKIT_EXTERN NSString * const NSShadowAttributeName NS_AVAILABLE(10_0, 6_0);
 
//文本特殊效果
UIKIT_EXTERN NSString *const NSTextEffectAttributeName NS_AVAILABLE(10_10, 7_0);
 
//文本附件,取值为NSTextAttachment对象,常用于文字图片混排
UIKIT_EXTERN NSString * const NSAttachmentAttributeName NS_AVAILABLE(10_0, 7_0);
 
//设置链接属性,点击后调用浏览器打开指定URL地址
UIKIT_EXTERN NSString * const NSLinkAttributeName NS_AVAILABLE(10_0, 7_0);
 
//设置基线偏移值,取值为 NSNumber (float),正值上偏,负值下偏
UIKIT_EXTERN NSString * const NSBaselineOffsetAttributeName NS_AVAILABLE(10_0, 7_0);
 
//设置下划线颜色
UIKIT_EXTERN NSString * const NSUnderlineColorAttributeName NS_AVAILABLE(10_0, 7_0);
 
//设置删除线颜色,取值为 UIColor 对象,默认值为黑色
UIKIT_EXTERN NSString * const NSStrikethroughColorAttributeName NS_AVAILABLE(10_0, 7_0);
 
// 设置字形倾斜度,取值为 NSNumber (float),正值右倾,负值左倾
UIKIT_EXTERN NSString * const NSObliquenessAttributeName NS_AVAILABLE(10_0, 7_0);
 
// 设置文本横向拉伸属性,取值为 NSNumber (float),正值横向拉伸文本,负值横向压缩文本
UIKIT_EXTERN NSString * const NSExpansionAttributeName NS_AVAILABLE(10_0, 7_0);
 
// 设置文字书写方向,从左向右书写或者从右向左书写
UIKIT_EXTERN NSString * const NSWritingDirectionAttributeName NS_AVAILABLE(10_6, 7_0);
 
// 设置文字排版方向,取值为 NSNumber 对象(整数),0 表示横排文本,1 表示竖排文本
UIKIT_EXTERN NSString * const NSVerticalGlyphFormAttributeName NS_AVAILABLE(10_7, 6_0);

NSUnderlineStyle

//  下面定义了下划线、删除线支持的样式
typedef NS_ENUM(NSInteger, NSUnderlineStyle) {
    NSUnderlineStyleNone                                    = 0x00,// 不设置下划线
    NSUnderlineStyleSingle                                  = 0x01,// 设置删除线为细单实线
    NSUnderlineStyleThick NS_ENUM_AVAILABLE(10_0, 7_0)      = 0x02, // 设置删除线为粗单实线
    NSUnderlineStyleDouble NS_ENUM_AVAILABLE(10_0, 7_0)     = 0x09,// 设置删除线为细双实线
    
    NSUnderlinePatternSolid NS_ENUM_AVAILABLE(10_0, 7_0)      = 0x0000, // 实线
    NSUnderlinePatternDot NS_ENUM_AVAILABLE(10_0, 7_0)        = 0x0100, // 点线
    NSUnderlinePatternDash NS_ENUM_AVAILABLE(10_0, 7_0)       = 0x0200,  // 虚线
    NSUnderlinePatternDashDot NS_ENUM_AVAILABLE(10_0, 7_0)    = 0x0300,
    NSUnderlinePatternDashDotDot NS_ENUM_AVAILABLE(10_0, 7_0) = 0x0400,
    
    NSUnderlineByWord NS_ENUM_AVAILABLE(10_0, 7_0)            = 0x8000
} NS_ENUM_AVAILABLE(10_0, 6_0);
 
typedef NS_ENUM(NSInteger, NSWritingDirectionFormatType) {
    NSWritingDirectionEmbedding     = (0 << 1),
    NSWritingDirectionOverride      = (1 << 1)
} NS_ENUM_AVAILABLE(10_11, 9_0);
 
// NSTextEffectAttributeName values
UIKIT_EXTERN NSString *const NSTextEffectLetterpressStyle NS_AVAILABLE(10_10, 7_0);

常用的一些场景

  • 1、处理简单的字符串,设置段落,字体,颜色
func handleParagraphStyle(){
    let string = "天道酬勤,持之以恒!天道酬勤,持之以恒天道酬勤,持之以恒天道酬勤,持之以恒天道酬勤,持之以恒天道酬勤,持之以恒,Cheer up!"
    //创建可变属性字符串
    let mutablaAttributedString = NSMutableAttributedString(string: string)

    let style = NSMutableParagraphStyle()
    style.lineSpacing = 10.0
    style.paragraphSpacing = 20.0
    //设置段落
    mutablaAttributedString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, string.characters.count))
    //设置字体
    mutablaAttributedString.addAttribute(NSFontAttributeName, value:UIFont.systemFont(ofSize: 20.0) , range: NSMakeRange(0, 10))
    //设置颜色
    mutablaAttributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: NSMakeRange(0, 10))

    let label = UILabel(frame: CGRect(x: 50, y: 150, width:300, height: 400))
    //设置段落样式的时候,numberOfLines必须为0
    label.numberOfLines = 0
    label.attributedText = mutablaAttributedString
    view.addSubview(label)
}

  • 2、如何在Label中显示图片和文字
//如何在Label中显示图片和文字
-(void)showImageWithAttributedString{
    
    //创建一个可变属性字符串
    NSMutableAttributedString *mutableAttribuedString=[[NSMutableAttributedString alloc]initWithString:@"Jack keep forward! You are the best! Cheer up! Man!"];
    
    //设置颜色和大小
    [mutableAttribuedString addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(5,11)];
    [mutableAttribuedString addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:20.0] range:NSMakeRange(5,11)];
    
    //创建NSTextAttachment对象,并设置图片
    NSTextAttachment *attachment=[[NSTextAttachment alloc]init];
    attachment.image=[UIImage imageNamed:@"ptjShare"];
    
    //设置图片
    [mutableAttribuedString replaceCharactersInRange:NSMakeRange(13,4) withAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
    
    //赋值给Label
    self.imageLabel.attributedText= mutableAttribuedString;
}
  • 3、加载HTML标签文本

因为解析的数据里面有html标签,就使用下面的代码把字符串转换成data进行初始化。

NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc] initWithData: [str dataUsingEncoding:NSUnicodeStringEncoding]
                                                                              options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
                                                                   documentAttributes:nil
                                                                                error:nil];

比如:加载本地html文件

NSURL *htmlString = [[NSBundle mainBundle]  URLForResource: @"string"  withExtension:@"html"];
NSAttributedString *stringWithHTMLAttributes = [[NSAttributedString alloc] initWithFileURL:htmlString
                                                                                       options:@{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType}
                                                                            documentAttributes:nil
                                                                                         error:nil];
textView.attributedText = stringWithHTMLAttributes;// you can use a label also

简单的html文件

<html>
  <head>
    <style type="text/css">
      body {
        font-size: 15px;
        font-family: Avenir, Arial, sans-serif;
      }
      .red {
        color: red;
      }
      .green {
        color: green;
      }
      .blue {
        color: blue;
      }
    </style>
  </head>
  <body>
    <span class="red">first</span><span class="green">second</span><span class="blue">third</span>
  </body>
</html>  

How do you use NSAttributedString?

  • 4、使用正则表达式查找字符并设置样式
NSMutableAttributedString *goodText = [[NSMutableAttributedString alloc] initWithString:articleText];

NSRange range = [articleText rangeOfString:@"\\[.+?\\]" options:NSRegularExpressionSearch|NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
    [goodText addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Georgia" size:16] range:range];
    [goodText addAttribute:NSForegroundColorAttributeName value:[UIColor brownColor] range:range];
}

NSString *regEx = [NSString stringWithFormat:@"%@.+?\\s", [self.article.titleText substringToIndex:0]];
range = [articleText rangeOfString:regEx options:NSRegularExpressionSearch|NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
    [goodText addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Georgia-Bold" size:20] range:range];
    [goodText addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:range];
}

[self.textView setAttributedText:goodText];
  • 5、迭代属性
let sentence = "the cat sat on the mat"

// 属性设置
let regularAttributes = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]
let largeAttributes = [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 24)]
let attributedSentence = NSMutableAttributedString(string: sentence, attributes: regularAttributes)

// 添加属性
attributedSentence.setAttributes(largeAttributes, range: NSRange(location: 0, length: 3))
attributedSentence.setAttributes(largeAttributes, range: NSRange(location: 8, length: 3))
attributedSentence.setAttributes(largeAttributes, range: NSRange(location: 15, length: 3))

// 迭代字体属性
attributedSentence.enumerateAttribute(.font, in: NSRange(0..<attributedSentence.length)) { value, range, stop in
    if let font = value as? UIFont {
        // make sure this font is actually bold
        if font.fontDescriptor.symbolicTraits.contains(.traitBold) {
            // it's bold, so make it red too
            attributedSentence.addAttribute(.foregroundColor, value: UIColor.red, range: range)
        }
    }
}
  • 6、Key的简单使用

1、下划线,涉及到的两个属性

NSUnderlineStyleAttributeName
NSUnderlineColorAttributeName

简单实现

UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 200, 60)];
[self.view addSubview:label];
NSMutableAttributedString * mutableAttriStr = [[NSMutableAttributedString alloc] initWithString:@"NSAttributedString"];
NSDictionary * attris = @{NSFontAttributeName:[UIFont boldSystemFontOfSize:12],
                          NSForegroundColorAttributeName:[UIColor redColor],
                          NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle),
                          NSUnderlineColorAttributeName:[UIColor blueColor],};
[mutableAttriStr setAttributes:attris range:NSMakeRange(0,mutableAttriStr.length)];
label.attributedText = mutableAttriStr;

2、描边,涉及到的两个属性

NSStrokeColorAttributeName
NSStrokeWidthAttributeName

替换属性字典即可

UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 200, 60)];
[self.view addSubview:label];
NSMutableAttributedString * mutableAttriStr = [[NSMutableAttributedString alloc] initWithString:@"NSAttributedString"];
NSDictionary * attris = @{NSForegroundColorAttributeName:[UIColor whiteColor],
                          NSStrokeColorAttributeName:[UIColor greenColor],
                          NSStrokeWidthAttributeName:@(2)};
[mutableAttriStr setAttributes:attris range:NSMakeRange(0,mutableAttriStr.length)];
label.attributedText = mutableAttriStr;

3、阴影效果

UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 200, 60)];
[self.view addSubview:label];
NSMutableAttributedString * mutableAttriStr = [[NSMutableAttributedString alloc] initWithString:@"NSAttributedString"];
NSShadow * shadow = [[NSShadow alloc] init];
shadow.shadowColor = [UIColor blueColor];
shadow.shadowBlurRadius = 2.0;
shadow.shadowOffset = CGSizeMake(1.0, 1.0);
NSDictionary * attris = @{NSShadowAttributeName: shadow};
[mutableAttriStr setAttributes:attris range:NSMakeRange(0,mutableAttriStr.length)];
label.attributedText = mutableAttriStr;

4、链接

点击文字打开链接

#import "ViewController.h"

@interface ViewController ()<UITextViewDelegate>

@end

@implementation ViewController


- (void)viewDidLoad {
    [super viewDidLoad];

    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    textView.scrollEnabled = NO;
    textView.editable = NO;
    textView.textContainer.lineFragmentPadding = 0;
    textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0);
    textView.delegate = self;
    [self.view addSubview:textView];

    NSMutableAttributedString * mutableAttriStr = [[NSMutableAttributedString alloc] initWithString:@"open url"];
    NSDictionary * attris = @{NSLinkAttributeName:[NSURL URLWithString:@"http://www.baidu.com"]};
    [mutableAttriStr setAttributes:attris range:NSMakeRange(0,mutableAttriStr.length)];
    textView.attributedText = mutableAttriStr;
}


- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction {
    return YES;
}

@end

还有更多的效果都是基于属性key,可以自己尝试

参考

NSAttributedString所有文本属性详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342