IOS UITextView支持輸入、複製、粘貼、剪切自定義表情

UITextView是ios的富文本編輯控件,除了文字還能夠插入圖片等。今天主要介紹一下UITextView對自定義表情的處理。ios

一、首先識別出文本中的表情文本,而後在對應的位置插入NSTextAttachment對象,該對象存放的就是自定義表情。正則表達式

 1 static NSString *emojiTextPttern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";
 2 
 3 _emojiDic = @{@"[大笑]":@"smile",@"[愛心]":@"love"};
 4 
 5 -(NSMutableAttributedString*)getEmojiText:(NSString*)content{
 6     NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:content attributes:self.typingAttributes];
 7     static NSRegularExpression *regExpress = nil;
 8     if(regExpress == nil){
 9         regExpress = [[NSRegularExpression alloc]initWithPattern:emojiTextPttern options:0 error:nil];
10     }
11     //經過正則表達式識別出emojiText
12     NSArray *matches = [regExpress matchesInString:content options:0 range:NSMakeRange(0, content.length)];
13     if(matches.count > 0){
14         for(NSTextCheckingResult *result in [matches reverseObjectEnumerator]){
15             NSString *emojiText = [content substringWithRange:result.range];
16             //構造NSTextAttachment對象
17             NSTextAttachment *attachment = [self createEmojiAttachment:emojiText];
18             if(attachment){
19                 NSAttributedString *rep = [NSAttributedString attributedStringWithAttachment:attachment];
20                 //在對應的位置替換
21                 [attributedString replaceCharactersInRange:result.range withAttributedString:rep];
22             }
23         }
24     }
25     return attributedString;
26 }

二、構造NSTextAttachment的過程爲:app

 1 -(NSTextAttachment*)createEmojiAttachment:(NSString*)emojiText{
 2     if(emojiText.length==0){
 3         return nil;
 4     }
 5     NSString *imageName = _emojiDic[emojiText];
 6     if(imageName.length == 0){
 7         return nil;
 8     }
 9     UIImage *image = [UIImage imageNamed:imageName];
10     if(image == nil){
11         return nil;
12     }
13     //把圖片縮放到符合當前textview行高的大小
14     CGFloat emojiWHScale = image.size.width/1.0/image.size.height;
15     CGSize emojiSize = CGSizeMake(self.font.lineHeight*emojiWHScale, self.font.lineHeight);
16     UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, emojiSize.width, emojiSize.height)];
17     imageView.image = image;
18     //防止模糊
19     UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, [UIScreen mainScreen].scale);
20     [imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
21     UIImage *emojiImage = UIGraphicsGetImageFromCurrentImageContext();
22     UIGraphicsEndImageContext();
23     EmojiTextAttachment *attachment = [[EmojiTextAttachment alloc]init];
24     attachment.image = emojiImage;
25     attachment.emojiText = emojiText;
26     attachment.bounds = CGRectMake(0, -3, emojiImage.size.width, emojiImage.size.height);
27     return attachment;
28 }

其中EmojiTextAttachment繼承了NSTextAttachment類,主要是爲了記住自定義表情對應的emojiText,在後面實現copy和cut須要用到。EmojiTextAttachment聲明爲:字體

1 @interface EmojiTextAttachment : NSTextAttachment
2 
3 /**
4  保存emojiText的值
5  */
6 @property (nonatomic, strong) NSString *emojiText;
7 @end

三、實現對自定義表情的粘貼atom

從新paste方法便可spa

 1 -(void)paste:(id)sender{
 2     UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
 3     if(defaultPasteboard.string.length>0){
 4         NSRange range = self.selectedRange;
 5         if(range.location == NSNotFound){
 6             range.location = self.text.length;
 7         }
 8         if([self.delegate textView:self shouldChangeTextInRange:range replacementText:defaultPasteboard.string]){
 9            NSAttributedString *newAttriString = [self getEmojiText:defaultPasteboard.string];
10            [self insertAttriStringToTextview:newAttriString];
11         }
12         return;
13     }
14     [super paste:sender];
15 }
16 
17 -(void)insertAttriStringToTextview:(NSAttributedString*)attriString{
18     NSMutableAttributedString *mulAttriString = [[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText];
19     NSRange range = self.selectedRange;
20     if(range.location == NSNotFound){
21         range.location = self.text.length;
22     }
23     [mulAttriString insertAttributedString:attriString atIndex:range.location];
24     self.attributedText = [mulAttriString copy];
25     self.selectedRange = NSMakeRange(range.location+attriString.length, 0);
26 }

四、實現自定義表情的拷貝和剪切code

拷貝和剪切自定義表情的時候,不是獲取自定義表情對應的圖片而是自定義表情對應的emojiText,這也是咱們在上面要定義EmojiTextAttachment類的緣由。具體代碼以下:對象

 1 -(void)copy:(id)sender{
 2     NSRange range = self.selectedRange;
 3     NSString *content = [self getStrContentInRange:range];
 4     if(content.length>0){
 5         UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
 6         [defaultPasteboard setString:content];
 7         return;
 8     }
 9     [super copy:sender];
10 }
11 -(void)cut:(id)sender{
12     NSRange range = self.selectedRange;
13     NSString *content = [self getStrContentInRange:range];
14     if(content.length>0){
15         [super cut:sender];
16         UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
17         [defaultPasteboard setString:content];
18         return;
19     }
20     [super cut:sender];
21 }
22 
23 /**
24  把textview的attributedText轉化爲NSString,其中把自定義表情轉化爲emojiText
25 
26  @param range 轉化的範圍
27  @return 返回轉化後的字符串
28  */
29 -(NSString*)getStrContentInRange:(NSRange)range{
30     NSMutableString *result = [[NSMutableString alloc]initWithCapacity:10];
31     NSRange effectiveRange = NSMakeRange(range.location,0);
32     NSUInteger length = NSMaxRange(range);
33     while (NSMaxRange(effectiveRange)<length) {
34         NSTextAttachment *attachment = [self.attributedText attribute:NSAttachmentAttributeName atIndex:NSMaxRange(effectiveRange) effectiveRange:&effectiveRange];
35         if(attachment){
36             if([attachment isKindOfClass:[EmojiTextAttachment class]]){
37                 EmojiTextAttachment *emojiAttachment = (EmojiTextAttachment*)attachment;
38                 [result appendString:emojiAttachment.emojiText];
39             }
40         }
41         else{
42             NSString *subStr = [self.text substringWithRange:effectiveRange];
43             [result appendString:subStr];
44         }
45     }
46     return [result copy];
47 }

經過上面的努力,咱們已經實現了全部的功能。可是咱們用起來的時候,會發現兩個問題:blog

一、在自定義表情的後面輸入文本,UITextview設置的屬性(好比字體大小,顏色等)都消失,又變成了默認屬性;繼承

二、在ios 10.11系統上,長按自定義表情的時候,keyboard會退出,而且彈出保存圖片的系統窗口,這樣的體驗也很差。

解決第一個問題:

咱們在初始化的時候保存一下UITextview的typingAttributes屬性,而後在每次UITextview的內容將要發生變化的時候,重置一下他的該屬性。

 1 @interface ViewController ()<UITextViewDelegate>
 2 @property (nonatomic, strong)CustomTextView *textView;
 3 
 4 @property (nonatomic, strong)NSDictionary *typingAttributes;
 5 @end
 6 
 7 -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
 8     textView.typingAttributes = self.typingAttributes;
 9     return YES;
10 }

解決第二個問題:

只須要實現一個delegate方法就行,直接返回NO

1 -(BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction{
2     return NO;
3 }
相關文章
相關標籤/搜索