UITextView編輯時插入自定義表情-簡單的圖文混編
前言
在iOS開發中,經常需要用UITextView作為編輯文字的輸入控制元件。
但是如何在編輯時插入自定義表情呢?就是像發微博時那樣?
本文簡單的用NSTextAttachment、NSAttributedString的特性,實現了
- 在UITextView中編輯文字時插入自定義表情圖片
- 同時可以返回帶有表情“替換符”的純文字字串。
示例
效果圖:
背景知識
- NSAttributedString及其子類,用於顯示富文字。
- NSTextAttachment,NSAttributedString的一種樣式類,可以在文字中顯示圖片。
- NSTextStorage,UITextView中的實際的文字封裝。(見參考中的UITextView文件)
表情與其標誌
首先需要明確的是,我們的自定義表情一定是有一一對應的“標誌”的,如“[/emoji_haha]”。
就是說,為了方便處理,方便在資料庫、網路傳輸中儲存、傳輸帶有表情圖片的文字,我們必須要為每種表情取特定的“名字”,資料庫中儲存的、網路傳輸的文字就只包含這些標誌名字就行,在顯示的時候做對應的替換。
如:
對應的純文字就是:
tutuge.me[/emoji_1]
插入並顯示錶情圖片
插入表情很簡單,直接例項化NSTextAttachment類,將需要的表情的UIImage例項賦值給NSTextAttachment的image屬性,然後用“[NSAttributedString attributedStringWithAttachment:]
如下:
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:”,其原型如下:
- (void)enumerateAttribute:(NSString *)attrName
inRange:(NSRange)enumerationRange
options:(NSAttributedStringEnumerationOptions)opts
usingBlock:(void (^)(id value,
NSRange range,
BOOL *stop))block
用處:
Executes the Block for the specified attribute run in the specified range.
看,就是這個方法~就能遍歷出NSTextAttachment物件了~
建立NSTextAttachment的子類
如何繫結NSTextAttachment所表示的表情和與其對應的標誌?建立子類嘛~直接在子類中增加屬性,儲存標誌不就行了。
如下:
@interface EmojiTextAttachment : NSTextAttachment
@property(strong, nonatomic) NSString *emojiTag;
@end
所以,這個時候,插入表情的程式碼應該就是下面這樣:
EmojiTextAttachment *emojiTextAttachment = [EmojiTextAttachment new];
//儲存表情標誌
emojiTextAttachment.emojiTag = emojiTag;
//設定表情圖片
emojiTextAttachment.image = emojiImage;
//插入表情
[textView.textStorage insertAttributedString:[NSAttributedString attributedStringWithAttachment:emojiTextAttachment]
atIndex:textView.selectedRange.location];
建立NSAttributedString的Category
最後,就是將這個遍歷表情、拼接最終文字字串的方法設定成NSAttributedString的自定義Category方法,以方便直接呼叫。
當然,這裡面有些細節的處理,如替換表情標誌時的字串偏移量計算等,看程式碼吧。
如下:
//NSAttributedString+EmojiExtension.h
@interface NSAttributedString (EmojiExtension)
- (NSString *)getPlainString;
@end
//NSAttributedString+EmojiExtension.m
@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) {
//檢查型別是否是自定義NSTextAttachment類
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來的強大(自己也在學習中)~
如果有更好地辦法,一定要告訴我啊~~~