zoukankan      html  css  js  c++  java
  • IOS UITextView支持输入、复制、粘贴、剪切自定义表情

    UITextView是ios的富文本编辑控件,除了文字还可以插入图片等。今天主要介绍一下UITextView对自定义表情的处理。

    1、首先识别出文本中的表情文本,然后在对应的位置插入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 }

    2、构造NSTextAttachment的过程为:

     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

    3、实现对自定义表情的粘贴

    重新paste方法即可

     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 }

    4、实现自定义表情的拷贝和剪切

    拷贝和剪切自定义表情的时候,不是获取自定义表情对应的图片而是自定义表情对应的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 }

    通过上面的努力,我们已经实现了所有的功能。但是我们用起来的时候,会发现两个问题:

    1、在自定义表情的后面输入文本,UITextview设置的属性(比如字体大小,颜色等)都消失,又变成了默认属性;

    2、在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 }
  • 相关阅读:
    Flutter-动画-原理篇
    Flutter-动画-实践篇
    Flutter-动画-概念篇
    Android-textview图文混排(网络图片)
    Android--解决图片保存到相册显示1970年1月1日 8:00的问题
    Android--使用JobService实现进程保活
    Android--获取手机联系人和Sim卡联系人
    git 代码服务器的网页版gitweb的搭建
    Android 内存管理中的 Shallow heap Retained heap
    欧几里德算法----最大公约数算法
  • 原文地址:https://www.cnblogs.com/yongbufangqi1988/p/8945643.html
Copyright © 2011-2022 走看看