前言在iOS开发中,经常需要用UITextView作为编辑文本的输入控件。 但是如何在编辑时插入自定义表情呢?就是像发微博时那样?
本文简单的用NSTextAttachment 、NSAttributedString 的特性,实现了
在UITextView中编辑文字时插入自定义表情图片
同时可以返回带有表情“替换符 ”的纯文本字符串。
示例本文代码工程地址:https://github.com/zekunyan/UITextViewDIYEmojiExample
效果图:
背景知识
NSAttributedString及其子类,用于显示富文本。
NSTextAttachment,NSAttributedString的一种样式类,可以在文本中显示图片。
NSTextStorage,UITextView中的实际的文本封装。(见参考中的UITextView文档)
表情与其标志首先需要明确的是,我们的自定义表情一定是有一一对应的“标志 ”的,如“[/emoji_haha] ”。
就是说,为了方便处理,方便在数据库、网络传输中保存、传输带有表情图片的文本,我们必须要为每种表情取特定的“名字 ”,数据库中储存的、网络传输的文本就只包含这些标志名字就行,在显示的时候做对应的替换。
如:
tutuge.me
对应的纯文本就是:
tutuge.me[/emoji_1]
插入并显示表情图片插入表情很简单,直接实例化NSTextAttachment 类,将需要的表情的UIImage实例赋值给NSTextAttachment的image属性,然后用“[NSAttributedString attributedStringWithAttachment:] ”方法实例化一个NSAttributedString的对象,插入到UITextView的textStorage对应的位置即可。
如下:
1 2 3 4 5 6 7 8 NSTextAttachment *emojiTextAttachment = [NSTextAttachment new ]; emojiTextAttachment.image = emojiImage; [textView.textStorage insertAttributedString: [NSAttributedString attributedStringWithAttachment: emojiTextAttachment] atIndex: textView.selectedRange.location];
这样,就能在UITextView当前光标位置插入表情图片了。
获取带有表情标志的文本字符串 难点NSTextAttachment被插入到NSAttributedString中的时候,就被当成了一个字符处理!!! 。 就是说,只从UITextView的text中,是找不回文本里面不同的表情所对应的标志的!
解决点
我们要能遍历出当前文本中所有的表情,也就是NSTextAttachment类。
我们要能知道遍历出的表情,对应的标志是什么。
遍历所有的NSTextAttachment类属性遍历,嗯,先看看Apple有没有提供相应的方法,能遍历NSAttributedString(及其子类)的属性的。查阅文档:NSAttributedString Class Reference ,可以找到这么一个方法:“- enumerateAttribute:inRange:options:usingBlock: ”,其原型如下:
1 2 3 4 - (void )enumerateAttribute:(NSString *)attrName inRange:(NSRange )enumerationRange options:(NSAttributedStringEnumerationOptions )opts usingBlock:(void (^)(id value, NSRange range, BOOL *stop))block
用处:
1 Executes the Block for the specified attribute run in the specified range.
看,就是这个方法~就能遍历出NSTextAttachment对象了~
创建NSTextAttachment的子类如何绑定NSTextAttachment所表示的表情和与其对应的标志?创建子类嘛~直接在子类中增加属性,保存标志不就行了。 如下:
1 2 3 @interface EmojiTextAttachment : NSTextAttachment@property (strong, nonatomic) NSString *emojiTag;@end
所以,这个时候,插入表情的代码应该就是下面这样:
1 2 3 4 5 6 7 8 9 10 11 EmojiTextAttachment *emojiTextAttachment = [EmojiTextAttachment new ]; emojiTextAttachment.emojiTag = emojiTag; emojiTextAttachment.image = emojiImage; [textView.textStorage insertAttributedString: [NSAttributedString attributedStringWithAttachment: emojiTextAttachment] atIndex: textView.selectedRange.location];
创建NSAttributedString的Category最后,就是将这个遍历表情、拼接最终文本字符串的方法设置成NSAttributedString的自定义Category方法,以方便直接调用。 当然,这里面有些细节的处理,如替换表情标志时的字符串偏移量计算等,看代码吧。
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @interface NSAttributedString (EmojiExtension )- (NSString *)getPlainString; @end @implementation NSAttributedString (EmojiExtension )- (NSString *)getPlainString { NSMutableString *plainString = [NSMutableString stringWithString:self .string]; __block NSUInteger base = 0 ; [self enumerateAttribute:NSAttachmentAttributeName inRange:NSMakeRange (0 , self .length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { if (value && [value isKindOfClass:[EmojiTextAttachment class ]]) { [plainString replaceCharactersInRange:NSMakeRange (range.location + base, range.length) withString:((EmojiTextAttachment *) value).emojiTag]; base += ((EmojiTextAttachment *) value).emojiTag.length - 1 ; } }]; return plainString; } @end
使用直接调用getPlainString方法即可。
总结其实本文也是来源于最近的项目需求,在网上一直找不到比较好的解决方案,就自己摸索出来一个。至于复杂的图文混合编辑,当然还是Core Text来的强大(自己也在学习中)~
如果有更好地办法,一定要告诉我啊~~~
参考
上一篇:Effective-Objective-C-读书笔记-Item-4-如何正确定义常量
下一篇:关于评论不见了=。=