日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ios开发text kit_iOS富文本(三)深入使用Text Kit

發布時間:2025/3/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ios开发text kit_iOS富文本(三)深入使用Text Kit 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在上一篇中介紹了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 *)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 *)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 NSTextStorage Tag下載

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 NSLayoutManager Tag下載

總結

以上是生活随笔為你收集整理的ios开发text kit_iOS富文本(三)深入使用Text Kit的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。