IOS UITextView支持输入、复制、粘贴、剪切自定义表情
UITextView是ios的富文本编辑控件,除了文字还可以插入图片等。今天主要介绍一下UITextView对自定义表情的处理。
1、首先识别出文本中的表情文本,然后在对应的位置插入NSTextAttachment对象,该对象存放的就是自定义表情。
 static NSString *emojiTextPttern = @"\\[[0-9a-zA-Z\\u4e00-\\u9fa5]+\\]";
 _emojiDic = @{@"[大笑]":@"smile",@"[爱心]":@"love"};
 -(NSMutableAttributedString*)getEmojiText:(NSString*)content{
     NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc]initWithString:content attributes:self.typingAttributes];
     static NSRegularExpression *regExpress = nil;
     if(regExpress == nil){
         regExpress = [[NSRegularExpression alloc]initWithPattern:emojiTextPttern options: error:nil];
     }
     //通过正则表达式识别出emojiText
     NSArray *matches = [regExpress matchesInString:content options: range:NSMakeRange(, content.length)];
     if(matches.count > ){
         for(NSTextCheckingResult *result in [matches reverseObjectEnumerator]){
             NSString *emojiText = [content substringWithRange:result.range];
             //构造NSTextAttachment对象
             NSTextAttachment *attachment = [self createEmojiAttachment:emojiText];
             if(attachment){
                 NSAttributedString *rep = [NSAttributedString attributedStringWithAttachment:attachment];
                 //在对应的位置替换
                 [attributedString replaceCharactersInRange:result.range withAttributedString:rep];
             }
         }
     }
     return attributedString;
 }
2、构造NSTextAttachment的过程为:
 -(NSTextAttachment*)createEmojiAttachment:(NSString*)emojiText{
     if(emojiText.length==){
         return nil;
     }
     NSString *imageName = _emojiDic[emojiText];
     if(imageName.length == ){
         return nil;
     }
     UIImage *image = [UIImage imageNamed:imageName];
     if(image == nil){
         return nil;
     }
     //把图片缩放到符合当前textview行高的大小
     CGFloat emojiWHScale = image.size.width/1.0/image.size.height;
     CGSize emojiSize = CGSizeMake(self.font.lineHeight*emojiWHScale, self.font.lineHeight);
     UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(, , emojiSize.width, emojiSize.height)];
     imageView.image = image;
     //防止模糊
     UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, [UIScreen mainScreen].scale);
     [imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
     UIImage *emojiImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     EmojiTextAttachment *attachment = [[EmojiTextAttachment alloc]init];
     attachment.image = emojiImage;
     attachment.emojiText = emojiText;
     attachment.bounds = CGRectMake(, -, emojiImage.size.width, emojiImage.size.height);
     return attachment;
 }
其中EmojiTextAttachment继承了NSTextAttachment类,主要是为了记住自定义表情对应的emojiText,在后面实现copy和cut需要用到。EmojiTextAttachment声明为:
@interface EmojiTextAttachment : NSTextAttachment /**
保存emojiText的值
*/
@property (nonatomic, strong) NSString *emojiText;
@end
3、实现对自定义表情的粘贴
重新paste方法即可
 -(void)paste:(id)sender{
     UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
     if(defaultPasteboard.string.length>){
         NSRange range = self.selectedRange;
         if(range.location == NSNotFound){
             range.location = self.text.length;
         }
         if([self.delegate textView:self shouldChangeTextInRange:range replacementText:defaultPasteboard.string]){
            NSAttributedString *newAttriString = [self getEmojiText:defaultPasteboard.string];
            [self insertAttriStringToTextview:newAttriString];
         }
         return;
     }
     [super paste:sender];
 }
 -(void)insertAttriStringToTextview:(NSAttributedString*)attriString{
     NSMutableAttributedString *mulAttriString = [[NSMutableAttributedString alloc]initWithAttributedString:self.attributedText];
     NSRange range = self.selectedRange;
     if(range.location == NSNotFound){
         range.location = self.text.length;
     }
     [mulAttriString insertAttributedString:attriString atIndex:range.location];
     self.attributedText = [mulAttriString copy];
     self.selectedRange = NSMakeRange(range.location+attriString.length, );
 }
4、实现自定义表情的拷贝和剪切
拷贝和剪切自定义表情的时候,不是获取自定义表情对应的图片而是自定义表情对应的emojiText,这也是我们在上面要定义EmojiTextAttachment类的原因。具体代码如下:
 -(void)copy:(id)sender{
     NSRange range = self.selectedRange;
     NSString *content = [self getStrContentInRange:range];
     if(content.length>){
         UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
         [defaultPasteboard setString:content];
         return;
     }
     [super copy:sender];
 }
 -(void)cut:(id)sender{
     NSRange range = self.selectedRange;
     NSString *content = [self getStrContentInRange:range];
     if(content.length>){
         [super cut:sender];
         UIPasteboard *defaultPasteboard = [UIPasteboard generalPasteboard];
         [defaultPasteboard setString:content];
         return;
     }
     [super cut:sender];
 }
 /**
  把textview的attributedText转化为NSString,其中把自定义表情转化为emojiText
  @param range 转化的范围
  @return 返回转化后的字符串
  */
 -(NSString*)getStrContentInRange:(NSRange)range{
     NSMutableString *result = [[NSMutableString alloc]initWithCapacity:];
     NSRange effectiveRange = NSMakeRange(range.location,);
     NSUInteger length = NSMaxRange(range);
     while (NSMaxRange(effectiveRange)<length) {
         NSTextAttachment *attachment = [self.attributedText attribute:NSAttachmentAttributeName atIndex:NSMaxRange(effectiveRange) effectiveRange:&effectiveRange];
         if(attachment){
             if([attachment isKindOfClass:[EmojiTextAttachment class]]){
                 EmojiTextAttachment *emojiAttachment = (EmojiTextAttachment*)attachment;
                 [result appendString:emojiAttachment.emojiText];
             }
         }
         else{
             NSString *subStr = [self.text substringWithRange:effectiveRange];
             [result appendString:subStr];
         }
     }
     return [result copy];
 }
通过上面的努力,我们已经实现了所有的功能。但是我们用起来的时候,会发现两个问题:
1、在自定义表情的后面输入文本,UITextview设置的属性(比如字体大小,颜色等)都消失,又变成了默认属性;
2、在ios 10.11系统上,长按自定义表情的时候,keyboard会退出,并且弹出保存图片的系统窗口,这样的体验也不好。
解决第一个问题:
我们在初始化的时候保存一下UITextview的typingAttributes属性,然后在每次UITextview的内容将要发生变化的时候,重置一下他的该属性。
@interface ViewController ()<UITextViewDelegate>
@property (nonatomic, strong)CustomTextView *textView; @property (nonatomic, strong)NSDictionary *typingAttributes;
@end -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
textView.typingAttributes = self.typingAttributes;
return YES;
}
解决第二个问题:
只需要实现一个delegate方法就行,直接返回NO
 -(BOOL)textView:(UITextView *)textView shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction{
     return NO;
 }
IOS UITextView支持输入、复制、粘贴、剪切自定义表情的更多相关文章
- mac复制粘贴剪切
		win下复制粘贴剪切: Ctrl+C,Ctrl+V,Ctrl+X; mac下lion之后已经有了一直让win用户吐槽的剪切功能: 复制粘贴剪切:Command+C,Command+V,Command+ ... 
- Vim 下的复制/粘贴/剪切/撤销
		一 了解 vim 有 12 个粘贴板,分别是 0.1.2.....9.a.“.+:用 :reg 命令可以查看各个粘贴板里的内容.在 vim 中简单用 y 命令只是复制到 "(双引号)粘贴板里 ... 
- linux下nano中复制粘贴剪切的快捷键是什么
		答: 1.复制:alt+6 2.剪切:ctrl+k 3.粘贴:ctrl+u 4.自由剪切: ctrl+6指定起始剪切位置,按上下左右键来选中内容,然后按下ctrl+k即可自由剪切 5.撤销: alt+ ... 
- 富文本框编辑器实现:a、支持图片复制粘贴;b、支持word复制粘贴图文。
		Chrome+IE默认支持粘贴剪切板中的图片,但是我要发布的文章存在word里面,图片多达数十张,我总不能一张一张复制吧?Chrome高版本提供了可以将单张图片转换在BASE64字符串的功能.但是无法 ... 
- iOS UITextView 根据输入text自适应高度
		转载自:http://www.cnblogs.com/tmf-4838/p/5380495.html #import "ViewController.h" @interface V ... 
- input 禁止 复制 粘贴 剪切 操作
		1.代码 <Input onCopy={(e)=>{ // 禁止拷贝 e.preventDefault(); }} onPaste={(e)=>{ // 禁止粘贴 e.prevent ... 
- VB中复制-粘贴-剪切键实现
		If Me.ActiveControl.GetType.BaseType.ToString = "System.Windows.Forms.TextBoxBase" Then Wi ... 
- ios开发之--仿(微信)自定义表情键盘
		先附上demo:https://github.com/hgl753951/CusEmoji.git 效果图如下: 
- 【转】MFC 自定义edit 限制输入十六进制内容 响应复制粘贴全选剪切的功能
		参考地址:MFC 自定义edit 限制输入内容 响应复制粘贴全选剪切的功能 Ctrl组合键ASCII码 ^Z代表Ctrl+z ASCII值 控制字符 AS ... 
随机推荐
- 使用 Vue 和 epub.js 制作电子书阅读器
			ePub 简介 ePub 是一种电子书的标准格式,平时我看的电子书大部分是这种格式.在手机上我一般用"多看"阅读 ePub 电子书,在 Windows 上找不到用起来比较顺心的软件 ... 
- Appium+python测试app实例
			Appium和selenium差不到,只是一个用于测web,一个用于测APP.下面记录一下我搭的测试框架,同样是基于PO模式,用的unittest. 最后测试报告如下: 1.1 代码结构 这 ... 
- vueJs 源码解析 (三) 具体代码
			vueJs 源码解析 (三) 具体代码 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那么今天我们就从这三 ... 
- centos7.0下的 systemctl 用法
			参考链接: http://man.linuxde.net/systemctl 
- JWT
			Web安全通讯之Token与JWT http://blog.csdn.net/wangcantian/article/details/74199762 javaweb多说本地身份说明(JWT)之小白技 ... 
- Python基础数据类型之列表和元组
			一.列表 list 列表是python中的基础数据类型之一,其他语言中也有类似于列表的数据类型,比如js中叫数组,他是以[]括起来,每个元素以逗号隔开,而且他里面可以存放各种数据类型比如: li ... 
- Web 项目报错No suitable driver found for jdbc:mysql://localhost:3306/book 的一个解决办法
			确认jar包加入到了build path中,然后注意版本是否与数据库相配,还要留意将jar包放入WEB-INF下的lib文件夹中 
- 归档(NSKeyedArchiver)的使用
			归档的使用,是归于使用保存数据,但是一些简单的数据,如数组,字典等基本的数据类型,往往不使用在归档中,归档和plist以及UserDefaults最大的区别就在于,前者可以存放自定义的数据类型,而后两 ... 
- 已操作文件的方式,新建一个用户alex
- JS面向对象特性和值类型与复合类型
			JS面向对象之特性已经值类型与复合类型 一些属性 空对象 空对象也是对象, 只是有存变量的变量名, 没有对象属性 var o ={}; 参数传递 值类型: 函数内外两个变量, 两个数据, 都不相同 ... 
