通过2个例子,复习下textview的相关知识
一.文字计算大小
NSString的这个函数:
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary *)attributes context:(nullable NSStringDrawingContext *)context NS_AVAILABLE(10_11, 7_0);
用法:
-(void) countBounding{
NSString * txt = @"大多来问我的朋友们其实都不是很清楚自己的定位,要么是简单的告诉我高考英语考了多少(亲爱的江苏卷的135和全国二卷的135并不是一个层次的好么……),要么简单说一句觉得自己英语很差。只有两个月你给我一句我英语基础不好,怎么才能过四六级,我真的不是神回答不出来的。所以,第一步,也是最最重要的一步,买一本四六级真题(个人买过星火英语的那个黑皮系列卷,不管什么国内的英语考试都可以来一套,很不错,安利一下)。";
CGSize size = CGSizeMake(100, 1000);
// CGSize size = CGSizeMake(1000, 100);
CGRect rect = [txt boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:14]} context:nil];
NSLog(@"rect:s%f, %f",rect.size.width, rect.size.height);
self.textView.text = txt;
self.textView.frame = CGRectMake( 0, 0, ceil(rect.size.width), ceil(rect.size.height));
}
重要参数:
size:
通常,计算出来的区域是以传入的size的宽度为准则的.在宽度填满的基础上,再计算高度.(文档说的)
所以把我们需要的宽度传入,然后高度写的尽量大,写小了也没关系.
options:
NSStringDrawingUsesLineFragmentOrigin 这个必写,文档说的
NSStringDrawingUsesFontLeading 计算行高时使用行距。(字体大小+行间距=行距)
NSStringDrawingUsesDeviceMetrics 计算时用象形文字的边框而不是印刷字体的边框
NSStringDrawingTruncatesLastVisibleLine 如果传入的size装不下所有文本,文本会被省略号结尾.前提是NSStringDrawingUsesLineFragmentOrigin必写,外加String的line break mode必须是NSLineBreakByWordWrapping或者NSLineBreakByCharWrapping
attributes 需要的NSAttributeString的特性
附上一张重要的图,说明NSAttributeString的某些属性,来源于官网:
二. 文字环绕图片
1. 吃点入门概念
如此好的官网不得不看!
TextKit目前和WebKit平级,上面是三个我们熟悉的文本显示控件
- NSTextContrainer : 规定了文字要画的矩形(可以是任意形状,NSBezierPath) ,它是UITextView等的属性
- NSTextStorage : 它是NSMutableAttributedString的子类,它规定了要写的text,以及它们的显示属性
-
NSLayoutManager : 负责把Unicode文字变成象形文字.
光看概念和框架只会得到一头雾水.上代码:
-(void ) testAttribute{
NSString * str = @"三个月说一门流利外语没问题,只要你每天不断练习听力、不断模仿着说,尽量学一些贴近生活的句子,毕竟学语言的目的不仅仅是为了考试,更多运用到生活之中。语言学习需要一小时、一小时的积累,不是大家想象中那样几天就可以掌握一门外语。这一点我很赞同,当初自己在学德语时,也是花了一段时间才能够顺利开口说句子。毕竟,你得花时间去学音标、音素,还得花时间去背单词,才会有接下来的开口说.";
NSString * str1 = @"培养自制力是一个漫长艰苦的过程。太多的诱惑随时可能让你功亏一篑。所谓的坚持,是心中纠结疑惑,还是继续在往前走,是自己战胜自己的过程。究竟怎样才能排除诸多干扰呢?其实关键就是要学会心理暗示,提前设想那些诱惑带来的种种负面影响,然后在心中一遍又一遍重复告诉自己。";
NSTextStorage * textStorage = [[NSTextStorage alloc] initWithString:str];
CGRect rect = CGRectInset(self.view.bounds, 10, 20);
//这一段代码很好的诠释了三者的纠结关系,自己体会-----------
NSLayoutManager * layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer * textContainer = [[NSTextContainer alloc] initWithSize:rect.size];
[layoutManager addTextContainer:textContainer];
UITextView * textView = [[UITextView alloc] initWithFrame:rect textContainer:textContainer];
//-----------
[self.view addSubview:textView];
//官网说这个必须写
[textStorage beginEditing];
//1. 通过AttributedString 设置attribute的属性 -- 这里最好写在textStorage初始化的时候,不然就赋值2次string了.是吧.而且实践得知,这样做显示出来非常慢,估计是因为替换了显示的文字的缘故
//这句话给文字赋上了一种风格
NSDictionary *attrsDic = @{NSTextEffectAttributeName: NSTextEffectLetterpressStyle};
NSMutableAttributedString * attributeStr = [[NSMutableAttributedString alloc] initWithString:str1 attributes:attrsDic];
[textStorage setAttributedString:attributeStr];
//2. 通过对textStorage的addAttribute:value:range来后期设置属性
// 这个让前三个字变红
[textStorage addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, 3)];
[textStorage endEditing];
}
2. 文字环绕
文字环绕其实就是运用了UITextStorage可以设置任意形状这一特性.它有个exclusionPaths属性,是排除文字的区域.官网这图很形象的告诉我们exclusionPaths存在时,文字的具体表现:
需要注意的是传入的rect必须是相对于textview的rect,而不是图片的frame.
用UIView的函数转换:
- (CGRect)convertRect:(CGRect)rect fromView:(nullable UIView *)view;
直接上代码:
-(void ) testSurround{
NSString * str = @"三个月说一门流利外语没问题,只要你每天不断练习听力、不断模仿着说,尽量学一些贴近生活的句子,毕竟学语言的目的不仅仅是为了考试,更多运用到生活之中。语言学习需要一小时、一小时的积累,不是大家想象中那样几天就可以掌握一门外语。这一点我很赞同,当初自己在学德语时,也是花了一段时间才能够顺利开口说句子。毕竟,你得花时间去学音标、音素,还得花时间去背单词,才会有接下来的开口说.清朝诗人王永彬曾说:身无饥寒,父母不曾亏我;人无长进,我以何对父母。努力,很多时候不是为了和别人竞争,只是因为我努力就会有收获,没有那么惊天动地,却可以给我带来更丰厚的一笔报酬,给老爸老妈买一件喜欢的衣服,世界那么大,我想带他们去看看。或许努力了依旧过不好自己的一生,改变不了这个社会,但至少,因为努力,我可以成为他们的依靠。或许这就是我们所有普通人努力的意义,为了更有尊严的活着,为了拥有更多选择的机会,为了遇见更好的自己,为了给爱我们的人一点回馈。";
UIView* innerView = [[UIView alloc] initWithFrame:CGRectMake(100,100,100, 100)];
[self.view addSubview:innerView];
NSTextStorage * textStorage = [[NSTextStorage alloc] initWithString:str];
CGRect rect = CGRectInset(self.view.bounds, 10, 20);
//这一段代码很好的诠释了三者的纠结关系,自己体会-----------
NSLayoutManager * layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer * textContainer = [[NSTextContainer alloc] initWithSize:rect.size];
[layoutManager addTextContainer:textContainer];
//-----------
UITextView* textView = [[UITextView alloc] initWithFrame:self.view.bounds textContainer:textContainer];
[self.view insertSubview:textView belowSubview:innerView];
//官网说这个必须写
[textStorage beginEditing];
//....
[textStorage endEditing];
CGRect relativeRect = [textView convertRect:innerView.frame fromView:self.view];
UIBezierPath * path = [UIBezierPath bezierPathWithRect:relativeRect];
textView.textContainer.exclusionPaths = @[path];
innerView.backgroundColor = [UIColor redColor];
}
效果:
Demo