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 ...
 
随机推荐
- PHP处理上传文件
			
HTML中使用type = 'file'类型的表单可以向服务器上传文件: 上传文件的表单必须在form中定义enctyp = 'multipart/form-data': HTML代码如下: < ...
 - Django REST framework+Vue 打造生鲜超市(一)
			
一.项目介绍 1.1.掌握的技术 Vue + Django Rest Framework 前后端分离技术 彻底玩转restful api 开发流程 Django Rest Framework 的功能实 ...
 - 常用cmd代码片段及.net core打包脚本分享
			
bat基础命令 注释:rem 注释~~ 输出:echo hello world 接收用户输入:%1 %2,第n个变量就用%n表示 当前脚本路径:%~dp0 当前目录路径:%cd% 设置变量:set c ...
 - Python内置函数(33)——any
			
英文文档: any(iterable) Return True if any element of the iterable is true. If the iterable is empty, re ...
 - java double相加
			
public class DoubleUtil { private static final int DEF_DIV_SCALE = 10; /** * 相加 * * @param d1 * @par ...
 - iot会议纪要 20180105
			
1.需求概述设备 <-->物接入 <--> 云端认证授权协议解析主题 端点endpoint(地址)->设备thing(用户)->身份principal(密码)-&g ...
 - notepad++运行Python
			
1.打开notepad++的菜单栏,点击run 2.输入cmd /k python "$(FULL_CURRENT_PATH)" & PAUSE & EXIT 3. ...
 - Python模块 - paramiko
			
paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能.这是一个第三方的软件包,使用之前需要安装. 1 基于用户名和密码的 sshclient 方式登录 # 建立一个s ...
 - java专业术语
			
java的(PO,VO,TO,BO,DAO,POJO)解释 PO(persistant object) 持久对象 在o/r映射的时候出现的概念,如果没有o/r映射,没有这个概念存在了.通常对应数据模型 ...
 - Django form表单
			
Form介绍 之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来.与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入, ...