iOS与Swift的那一个NS(Mutable)AttributedString

前言

这几天在项目中用到了一点图文混排的内容。但是如果使用github上面那些大神们的框架有一点大材小用,因为关于图文混排的内容就有那么一点,所以自己仔细研究了下NSAttributedString这个类,虽然他和 NSString看着相同,但是用法还是有很大的区别。现特写于此,一方面为了自己加深记忆,另一方面如果有对这方面知识点不理解的童鞋,可以参考一下我的理解。(本文具体是对NSAttributedString属性,方法的描述和实例),这里以OC为例进行的,如果需要Swift方面的,可以下载Demo(Swift版)进行参考。


正文

我想了好久不知道怎么开始这一块,最后绝对跟着苹果的API文档顺序走,这样可能会好一点。我去看一个类的第一眼看的一定是这个类的构造方法,因为只有存在了才有进行下一步的可能性。Demo下载(iOS版)   Demo下载(Swift版)


NSAttributedString

构造方法:

//直接创建

- (instancetype)initWithString:(NSString *)str;

//创建并附带属性

- (instancetype)initWithString:(NSString *)str attributes:(nullable NSDictionary*)attrs;

//加载一条已经存在的

NSAttributedString- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr;

这三个构造方法只要大家对nsstring熟悉,应该都会大致了解他们的意思和使用的不同。代码实例如下:

//构造方法

//原始数据

NSString *originStr = @"某农场爆发疯牛病,一女记者闻讯赶到,采访农场主:“请问这疯牛病是从何而来的“你想想,每天都有人来捏你的XX,但是又不和你做ai,你会不会疯掉“";

//第一种

NSAttributedString *string1 = [[NSAttributedString alloc]                              initWithString:originStr];textView.attributedText = string1;

//第二种

NSAttributedString *string2 = [[NSAttributedString alloc]                              initWithString:originStr                              attributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];textView.attributedText = string2;

//第三种

NSAttributedString *string3 =[[NSAttributedString alloc]                              initWithAttributedString:string2];textView.attributedText = string3;

用一个UITextView显示内容,在这里我们可以看出来,这几种构造方法的不同之处。第一种是直接用字符串创建,第二种在你创建的时候可以直接给他一个属性值,第三种是直接加载一个已经存在的NSAttributedString类型。

//判断两个NSAttributedString是否相等

-(BOOL)isEqualToAttributedString:(NSAttributedString *)other;

这里所说的相等,不是内容相等就可以,必须所设置的内容的属性也要相等才可以。代码如下:

NSAttributedString *string4 = [[NSAttributedString alloc]initWithString:originStrattributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];

//判断两个NSAttributedString是否相等

BOOL flag = [string1 isEqualToAttributedString:string2];

NSLog(@"flag === %i",flag);

BOOL flag2 = [string4 isEqualToAttributedString:string3];

NSLog(@"flag2 === %i,string4=%p,---string3=%p",flag2,string4,string3);

//NSObjec的方法

BOOL flag3 = [string4 isEqual:string3];

NSLog(@"flag3 === %i,string4=%p,---string3=%p",flag3,string4,string3);

在这里创建是string4的目的就是看一下,这个方法判断的相等与字符串的地址有没有关系,结果显示,没有关系,只要内容与属性相等,返回的结果就是yes。

//截取字符

-(NSAttributedString *)attributedSubstringFromRange:(NSRange)range;  

  这个方法的作用就是把本身的字符截取后赋予其他字符,代码如下:

//截取

NSAttributedString *string5 = [string4 attributedSubstringFromRange:NSMakeRange(0, 10)];

在这里就是把string4的从0到10的字符截取,赋予string5.

NSAttributedString的方法基本就是这些,还有几个方法是关于内容的遍历,查看的方法

- (nullable id)attribute:(NSString *)attrName atIndex:(NSUInteger)location effectiveRange:(nullable NSRangePointer)range;

- (NSDictionary*)attributesAtIndex:(NSUInteger)location longestEffectiveRange:(nullable NSRangePointer)range inRange:(NSRange)rangeLimit;

- (nullable id)attribute:(NSString *)attrName atIndex:(NSUInteger)location longestEffectiveRange:(nullable NSRangePointer)range inRange:(NSRange)rangeLimit;

- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(NSAttributedStringEnumerationOptions)opts usingBlock:(void (^)(NSDictionary*attrs, NSRange range, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(NSAttributedStringEnumerationOptions)opts usingBlock:(void (^)

他们的作用在我看来最大的用处之一就是输入表情显示的时候去遍历查看用的。这三个方法我没有深究,现在我还没有用到。

我们都知道,既然有一个不可变的NSAttributedString,一定会有一个对应的可变的这个类所对应的方法(苹果一贯如此)。所以NSMutableAttributedString出现了,而且我们平时使用的时候应该NSMutableAttributedString用的是最多的,因为他可以做增,删,改这些工作,而这些在NSAttributedString中是不具备的。


NSMutableAttributedString

首先说构造方法,因为他是继承自NSAttributedString的,所以他可以拥有NSAttributedString的所有的方法。(你再问我怎么知道他们是继承关系的??,请看下面官方API代码)

@interface NSMutableAttributedString : NSAttributedString

创建一个可变的:

NSMutableAttributedString *muString1 = [[NSMutableAttributedString alloc]                          initWithString:originStr];

也可以用

//官方API

- (void)setAttributedString:(NSAttributedString *)attrString;

这个方法增加一个字符串。代码如下:

[muString1 setAttributedString:string2];

增:

增加的方式有几种,第一种直接追加

//官方API

- (void)appendAttributedString:(NSAttributedString *)attrString;

这个方法是在字符串的末尾直接追加字符(不能是普通的字符串,看API 方法后面的属性提示),代码如下:

//追加

[muString1 appendAttributedString:string1];

第二种是插入

- (void)insertAttributedString:(NSAttributedString *)attrString atIndex:(NSUInteger)loc;

这个方法就是在原来内容中的某个地方插入一段字符,代码如下:

//插入内容(富文本)

[muString1 insertAttributedString:string5 atIndex:muString1.length];

删:

删除字符就有一个方法:

//API

- (void)deleteCharactersInRange:(NSRange)range;

代码如下:

//删除内容

[muString1 deleteCharactersInRange:NSMakeRange(0, 200)];

改:

我们来看一下,NSMutableAttributedString的改这个特性系统

API

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;

- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(NSAttributedString *)attrString;

这两个方法的的区别就是一个使用普通字符串替换原来的字符,一个使用NSAttributedString类型的字符串替换原来的字符。代码如下:

NSMutableAttributedString *muString1 = [[NSMutableAttributedString alloc]                                            initWithString:originStr];

//内容代替

[muString1 replaceCharactersInRange:NSMakeRange(0, 10) withString:@"hello,world"];

//替代

[muString1 replaceCharactersInRange:NSMakeRange(0, 10) withAttributedString:string1];

接下来我们要进入使用NSMutableAttributedString的最重要的内容了,给我们的字符串内容增加各种显示属性:颜色,大小,下划线……。

设置属性的方法:

- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;- (void)addAttributes:(NSDictionary*)attrs range:(NSRange)range;

这两个方法感觉就是NSMutableAttributedString的精华所在,是他与普通的字符串的最大的区别之处之一(还有图文混排这个区别)。

我们可以这样给某段字符串一个大小:

//字体大小

[muString1 addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:35] range:NSMakeRange(0, muString1.length)];

我们也可以这样给某段字符串一个字一颜色:

//字体颜色

[muString1 addAttribute:NSForegroundColorAttributeName value:[UIColor lightGrayColor] range:NSMakeRange(0, 20)];

我们又可以这样给某段字符串一个背景颜色:

//字体背景色

[muString1 addAttribute:NSBackgroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(20, 10)];

我们可以给某段字符串一个下划线显示:

//下划线

[muString1 addAttribute:NSUnderlineStyleAttributeName value:@(1) range:NSMakeRange(0, 20)];

感觉下划线颜色不好看,好的,来换个下划线颜色:

//下划线颜色

[muString1 addAttribute:NSUnderlineColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0, 10)];

给某段字符串删除线显示(个人感觉在电商app里面,原价那个属性最适合这个):

//删除线

[muString1 addAttribute:NSStrikethroughStyleAttributeName value:@(1) range:NSMakeRange(40, 10)];

来点高级的,做个边线(就是字体中空的样式):

//边线宽度

[muString1 addAttribute:NSStrokeWidthAttributeName value:@(1) range:NSMakeRange(10, 30)];

给边线来个颜色(必须有边线宽度才会有效果):

//边线颜色,必须有边线宽度

[muString1 addAttribute:NSStrokeColorAttributeName value:[UIColor blueColor] range:NSMakeRange(10, 10)];

最后,来个阴影效果:

//阴影

NSShadow *shadow = [[NSShadow alloc]init];

shadow.shadowColor = [UIColor purpleColor];

shadow.shadowOffset = CGSizeMake(0, 2);

[muString1 addAttribute:NSShadowAttributeName value:shadow range:NSMakeRange(0, 50)];

好了,演示的就这么多吧,还有好多属性,童鞋自己去查一下就行了。

上面演示的都是加载一个属性的方法,我们也可以以字典的方式一次同时加载多个属性。代码如下:

[muString1 addAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:20],NSBackgroundColorAttributeName:[UIColor yellowColor]} range:NSMakeRange(0, muString1.length)];

有一个需要注意,排版这个属性NSVerticalGlyphFormAttributeName。我用了一下但是显示没有反应,上网查了下,原来在ios上这个属性只显示默认的横版。

如果有的属性你不想用了,又不知道在哪写的了,那么接下来这个方法正好是你需要的:

- (void)removeAttribute:(NSString *)name range:(NSRange)range;

移除对应的属性,代码如下:

//移除属性

[muString1 removeAttribute:NSForegroundColorAttributeName range:NSMakeRange(0, 20)];

NSParagraphStyleAttributeName 这个属性我上网查了好久,但是每次使用都是失败,说是段落属性,看了api,也就是两个构造,几个属性,但是就是用不对……。


图文混排

首先说一下思路就是把图片插入或者追加到NSMutableAttributedString字符串里面。但是我们知道NSMutableAttributedString只能插入或者追加本类型的内容,那么我们怎么把图片插入呢,这里我们就要用到NSTextAttachment这个类。

NSTextAttachment这个类里面只有几个方法和属性,大家可以去看一下,这里不再多说。

插入图片代码如下:

//插入图片,与字体大小不一样

NSTextAttachment *attchment = [[NSTextAttachment alloc]init];

attchment.image = [UIImage imageNamed:@"share.jpg"];

NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:attchment];

[muString1 insertAttributedString:imageString atIndex:20];

用完这个方法Run一下你会发现图片的大小显示是以真实的大小显示的,那么我们怎么让他适应字体大小呢,我现在有两种办法。

一,自己去改变图片大小,代码如下:

NSTextAttachment *attchment = [[NSTextAttachment alloc]init];

UIImage *icon = [UIImage imageNamed:@"share.jpg"];

attchment.image = [self imageWithImage:icon scaleToSize:CGSizeMake(20, 20)];

NSAttributedString *imageString2 = [NSAttributedString attributedStringWithAttachment:attchment];

[muString1 insertAttributedString:imageString2 atIndex:20];

//修改图片大小

- (UIImage *)imageWithImage:(UIImage *)image scaleToSize:(CGSize)size

{

UIImage *newImage = nil;

UIGraphicsBeginImageContextWithOptions(size, false, 0.0);

[image drawInRect:CGRectMake(0, 0, size.width, size.height)];

newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return newImage;

}

这种方法是自己修改图片的大小去适应字体大小,比较麻烦。还有一种方法,自己继承NSTextAttachment这个类,去实现一个NSTextAttachment的方法,代码如下:

@implementation SYFTextAttachment

//让加载的内容与对应的富文本大小对应

-(CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(CGRect)lineFrag glyphPosition:(CGPoint)position characterIndex:(NSUInteger)charIndex

{

return CGRectMake(0, 0, lineFrag.size.height, lineFrag.size.height);

}

在使用的时候导入你自己写的这个继承类,然后写入对应的代码:

//插入图片,与字体大小一样

SYFTextAttachment *syfattchment = [[SYFTextAttachment alloc]init];

syfattchment.image = [UIImage imageNamed:@"share.jpg"];

NSAttributedString *imageString3 = [NSAttributedString attributedStringWithAttachment:syfattchment];

[muString1 insertAttributedString:imageString3 atIndex:60];


结语

本篇结束,我只是一个小菜鸟,写下来的最大的作用怕自己以后忘了。里面有不对的地方,希望指出,我立马改正。最后祝大家新年快乐!!!

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

推荐阅读更多精彩内容