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支持输入、复制、粘贴、剪切自定义表情的更多相关文章

  1. mac复制粘贴剪切

    win下复制粘贴剪切: Ctrl+C,Ctrl+V,Ctrl+X; mac下lion之后已经有了一直让win用户吐槽的剪切功能: 复制粘贴剪切:Command+C,Command+V,Command+ ...

  2. Vim 下的复制/粘贴/剪切/撤销

    一 了解 vim 有 12 个粘贴板,分别是 0.1.2.....9.a.“.+:用 :reg 命令可以查看各个粘贴板里的内容.在 vim 中简单用 y 命令只是复制到 "(双引号)粘贴板里 ...

  3. linux下nano中复制粘贴剪切的快捷键是什么

    答: 1.复制:alt+6 2.剪切:ctrl+k 3.粘贴:ctrl+u 4.自由剪切: ctrl+6指定起始剪切位置,按上下左右键来选中内容,然后按下ctrl+k即可自由剪切 5.撤销: alt+ ...

  4. 富文本框编辑器实现:a、支持图片复制粘贴;b、支持word复制粘贴图文。

    Chrome+IE默认支持粘贴剪切板中的图片,但是我要发布的文章存在word里面,图片多达数十张,我总不能一张一张复制吧?Chrome高版本提供了可以将单张图片转换在BASE64字符串的功能.但是无法 ...

  5. iOS UITextView 根据输入text自适应高度

    转载自:http://www.cnblogs.com/tmf-4838/p/5380495.html #import "ViewController.h" @interface V ...

  6. input 禁止 复制 粘贴 剪切 操作

    1.代码 <Input onCopy={(e)=>{ // 禁止拷贝 e.preventDefault(); }} onPaste={(e)=>{ // 禁止粘贴 e.prevent ...

  7. VB中复制-粘贴-剪切键实现

    If Me.ActiveControl.GetType.BaseType.ToString = "System.Windows.Forms.TextBoxBase" Then Wi ...

  8. ios开发之--仿(微信)自定义表情键盘

    先附上demo:https://github.com/hgl753951/CusEmoji.git 效果图如下:

  9. 【转】MFC 自定义edit 限制输入十六进制内容 响应复制粘贴全选剪切的功能

    参考地址:MFC 自定义edit 限制输入内容 响应复制粘贴全选剪切的功能   Ctrl组合键ASCII码 ^Z代表Ctrl+z                     ASCII值 控制字符  AS ...

随机推荐

  1. AngularJS1.X学习笔记9-自定义指令(中)

    今天好大的雨啊!上一节中,我们的指令中的工厂函数中都是返回了一个叫做链接函数的工人函数,事实上我们的工厂函数也是可以返回一个对象,这个对象里面可以包含很多的属性,这使得我们可以创建更加强大的指令. 一 ...

  2. redis入门(14)redis集群下的数据分区存储

    redis入门(10)redis集群下的数据分区存储

  3. 爬虫必备 User-Agent 列表

    USER_AGENTS = [ "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR ...

  4. python打包压缩文件夹zip+组装文件夹

    无意间想到的一个需求,然后就顺手写了写,留下来,方便以后用 列表版:(基本没用,仅提供思路,字典版稍微改动可以直接用) 大体需求: 把重复的文件名进行改名,达到浏览器下载相同文件的效果 下载完成后再把 ...

  5. C语言 左值、右值

    左值就是在赋值中可以放在赋值操作符两边的值 右值则是只可以放在赋值操作符右边的值 ++i是直接给i变量加1,然后返回i本身,因为i是变量,所以可以被赋值,因此是左值表达式i++现产生一个临时变量,记录 ...

  6. Tensorflow会话Session

    转载自: http://blog.csdn.net/Hanging_Gardens/article/details/72784392 https://www.cnblogs.com/hypnus-ly ...

  7. day3 自定义指令详解

    在angular中,Directive,自定义指令的学习,可以更好的理解angular指令的原理,当angular的指令不能满足你的需求的时候,嘿嘿,你就可以来看看这篇文章,自定义自己的指令,可以满足 ...

  8. 学习react系列(八)—— mixins迁移

    先来介绍一下mixins(混入) 先来看一段代码: const mixin = function(obj, mixins) { const newObj = obj; newObj.prototype ...

  9. reportng优化

    本来呢,我是看到报告中没有输出@Test的description 的属性,想优化一下,没想到在找reportng的源码的时候,发现一个大神也优化了reportNG,他优化了下面几个内容: 1).测试结 ...

  10. [HNOI 2003]消防局的设立

    Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来 连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成 ...