前言
这几天在项目中用到了一点图文混排的内容。但是如果使用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];
结语
本篇结束,我只是一个小菜鸟,写下来的最大的作用怕自己以后忘了。里面有不对的地方,希望指出,我立马改正。最后祝大家新年快乐!!!
网友评论