iOS富文本(三)深入使用Text Kit
2015-12-02 23:23
691 查看
在上一篇中介绍了
所要我们深入使用
因为这些方法实际上
继承
上面实现的方法里代码都加上了
根据上面提供的模版添加特殊处理的代码
每次编辑都会调用
只要文本中出现指定的关键字字体就会变红,输入指定的关键字字体也会变红。
实现效果
代码在github
更改字体绘制与字体背景颜色只需要重写下面的两个方法
下面例子会实现这样的功能,只要文本中有纯数字或者输入纯数字那么这段数字不显示出来,用黑色的遮罩挡住。
首先在
上面的代码主要为纯数字的字符串添加一个
再重写
下面重写
实现效果
这种遮罩是动态的,只要输入是纯数字那么
代码在github
Text Kit的三种基本组件的关系并且简单的实现了怎么使用这三种基本组件,本片将深入的去使用这三种基本组件。
NSTextStorage
NSTextStorage是
NSMutableAttributedString的子类,根据
苹果官方文档描述是
semiconcrete子类,因为
NSTextStorage没有实现
NSMutableAttributedString中的方法,所以说
NSTextStorage应该是
NSMutableAttributedString的类簇。
所要我们深入使用
NSTextStorage不仅要继承
NSTextStorage类还要实现
NSMutableAttributedString的下面方法
- (NSString *)string - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range - (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
因为这些方法实际上
NSTextStorage并没有实现然而我们断然不知道
NSMutableAttributedString是如何实现这些方法,所以我们继承
NSTextStorage并实现这些方法最简单的莫过于在
NSTextStorage类中实例化一个
NSMutableAttributedString对象然后调用
NSMutableAttributedString对象的这些方法来实现
NSTextStorage类中的这些方法
@interface LSYTextStorage : NSTextStorage @property (nonatomic,strong) NSMutableAttributedString *attributedString; @end
继承
NSTextStorage后都会实现下面的代码,如果要做一些特殊的处理知道在下面的代码里添加就可以了
#import "LSYTextStorage.h" @interface LSYTextStorage () @property (nonatomic,strong) NSMutableAttributedString *attributedString; @end @implementation LSYTextStorage - (instancetype)init { self = [super init]; if (self) { _attributedString = [[NSMutableAttributedString alloc] init]; } return self; } -(NSString *)string{ return [_attributedString string]; } - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(nullable NSRangePointer)range { return [_attributedString attributesAtIndex:location effectiveRange:range]; } -(void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str { [self beginEditing]; [_attributedString replaceCharactersInRange:range withString:str]; [self edited:NSTextStorageEditedAttributes|NSTextStorageEditedCharacters range:range changeInLength:str.length-range.length]; [self endEditing]; } -(void)setAttributes:(NSDictionary<NSString *,id> *)attrs range:(NSRange)range { [self beginEditing]; [_attributedString setAttributes:attrs range:range]; [self edited:NSTextStorageEditedAttributes range:range changeInLength:0]; [self endEditing]; } @end
上面实现的方法里代码都加上了
beginEditing,
edited:range:changeInLength:,
endEditing的方法,这样做主要是通知它的 Layout Manager 发生了变化来计时调整布局
根据上面提供的模版添加特殊处理的代码
#import "LSYTextStorage.h" @interface LSYTextStorage () @property (nonatomic,strong) NSMutableAttributedString *attributedString; @end @implementation LSYTextStorage - (instancetype)init { self = [super init]; if (self) { _attributedString = [[NSMutableAttributedString alloc] init]; } return self; } -(NSString *)string{ return [_attributedString string]; } - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(nullable NSRangePointer)range { return [_attributedString attributesAtIndex:location effectiveRange:range]; } -(void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str { [self beginEditing]; [_attributedString replaceCharactersInRange:range withString:str]; [self edited:NSTextStorageEditedAttributes|NSTextStorageEditedCharacters range:range changeInLength:str.length-range.length]; [self endEditing]; } -(void)setAttributes:(NSDictionary<NSString *,id> *)attrs range:(NSRange)range { [self beginEditing]; [_attributedString setAttributes:attrs range:range]; [self edited:NSTextStorageEditedAttributes range:range changeInLength:0]; [self endEditing]; } -(void)processEditing { NSRange lineRange = NSUnionRange(self.editedRange, [self.string lineRangeForRange:self.editedRange]); //正在编辑的整个段落范围 [self.attributedString.string enumerateSubstringsInRange:lineRange options:NSStringEnumerationByWords usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) { if ([substring isEqualToString:@"GGGHub"]) { [self setAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]} range:substringRange]; //当出现GGGHub单词时字体变红 } else{ [self setAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]} range:substringRange]; //默认字体是黑色 } }]; [super processEditing]; } @end
每次编辑都会调用
-(void)processEditing的方法,然后遍历整段修改的文字当出现
GGGHub的单词时显示红色字体。
#import "ViewController.h" #import "LSYTextStorage.h" @interface ViewController () { LSYTextStorage *textStroage; //需要声明为全局变量,否则出了作用域后就释放掉了 } @property (weak, nonatomic) IBOutlet UITextView *textView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; NSString *str = _textView.text; textStroage = [[LSYTextStorage alloc] init]; [textStroage replaceCharactersInRange:NSMakeRange(0, 0) withString:str]; [textStroage addLayoutManager:self.textView.layoutManager]; //替换textView的textStroage属性 }
只要文本中出现指定的关键字字体就会变红,输入指定的关键字字体也会变红。
实现效果
代码在github
NSTextStorageTag下载
NSLayoutManager
布局管理器主要用来绘制字体的。NSTextStorage虽然能够改变字体的样式但是更改不了字体绘制的方式。我们可以继承
NSLayoutManager来更改字体绘制。对于某些特定的字段可能不需要显示比如加密文本,或者用图片替换这些字段,或者給这些字段添加一些背景,这时只要重写
NSLayoutManager中的某些方法可以很简单的实现。
更改字体绘制与字体背景颜色只需要重写下面的两个方法
- (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin; //绘制字形背景 - (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin; //绘制字形
下面例子会实现这样的功能,只要文本中有纯数字或者输入纯数字那么这段数字不显示出来,用黑色的遮罩挡住。
首先在
LSYTextStorage.m文件中更改
processEditing函数
-(void)processEditing { NSRange lineRange = NSUnionRange(self.editedRange, [self.string lineRangeForRange:self.editedRange]); NSString *regexNumber = @"^-?[0-9]\\d*$"; NSPredicate *predicateNumber = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regexNumber]; //正则表达式,判断是否为纯数字 [self.attributedString.string enumerateSubstringsInRange:lineRange options:NSStringEnumerationByWords usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) { NSLog(@"%@",substring); if ([substring isEqualToString:@"GGGHub"]) { [self setAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]} range:substringRange]; } /** * 如果是纯数字給这段字符串添加LSYSecretAttribute属性为了绘制字形时查找 */ else if ([predicateNumber evaluateWithObject:substring]){ [self setAttributes:@{@"LSYSecretAttribute":@"secretAttribute"} range:substringRange]; } else{ [self setAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]} range:substringRange]; } }]; [super processEditing]; }
上面的代码主要为纯数字的字符串添加一个
LSYSecretAttribute的属性,当
NSLayoutManager开始绘制字形时可以方便找到这段字符串然后在这段字符串的范围绘制黑色遮罩
再重写
NSLayoutManager的方法前
下面重写
NSLayoutManager的
drawGlyphsForGlyphRange方法
-(void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin { NSRange range = [self characterRangeForGlyphRange:glyphsToShow actualGlyphRange:NULL]; [self.textStorage enumerateAttribute:@"LSYSecretAttribute" inRange:range options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) { //找到在LSYTextStorage中自定的LSYSecretAttribute属性 if ([value isEqualToString:@"secretAttribute"]) { NSRange glyphRange = [self glyphRangeForCharacterRange:range actualCharacterRange:NULL]; NSTextContainer * container = [self textContainerForGlyphAtIndex:glyphRange.location effectiveRange:NULL]; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); //保存当前的绘图配置信息 CGContextTranslateCTM(context, origin.x, origin.y); //转换初始坐标系到绘制字形的位置 [[UIColor blackColor] setFill]; CGRect rect = [self boundingRectForGlyphRange:glyphRange inTextContainer:container]; [self drawSecret:rect]; //开始绘制 CGContextRestoreGState(context); //恢复绘图配置信息 } else { [super drawGlyphsForGlyphRange:range atPoint:origin]; } }]; }
实现效果
这种遮罩是动态的,只要输入是纯数字那么
NSLayoutManager的对象就不会对其进行绘制,而用黑色的遮罩挡住。
代码在github
NSLayoutManagerTag下载
相关文章推荐
- iOS富文本(三)深入使用Text Kit
- iOS内存管理笔记 by STP
- OSX 10.10+Xcode5.1 无法启动或者安装应用程序到iOS 6.1 simulator
- 03-加入苹果开发者计划
- iOS委托理解
- IOS多线程
- iOS runtime原理
- ios runtime
- IOS-TableView 方法
- iOS 8 新特性总结
- iOS 9开发(适配)中需要注意的事项总结
- iOS 动画
- ios 获取屏幕的属性和宽度
- 如何让iOS 保持界面流畅?这些技巧你知道吗
- (十四)关于#include<iostream>
- IOS的一些手势方法(手势的tag值 绝对值 偏移量 中心点 等等)
- iOS 音频
- iOS 9开发(适配)中需要注意的事项总结
- IOS几种类型的动画
- iOS开发讯飞语音SDK使用 error code:10111 解决方案