1. 程式人生 > >UITextView編輯時插入自定義表情-簡單的圖文混編

UITextView編輯時插入自定義表情-簡單的圖文混編

前言

在iOS開發中,經常需要用UITextView作為編輯文字的輸入控制元件。
但是如何在編輯時插入自定義表情呢?就是像發微博時那樣?

本文簡單的用NSTextAttachmentNSAttributedString的特性,實現了

  • 在UITextView中編輯文字時插入自定義表情圖片
  • 同時可以返回帶有表情“替換符”的純文字字串。

示例

效果圖:

imageimage

背景知識

  • NSAttributedString及其子類,用於顯示富文字。
  • NSTextAttachment,NSAttributedString的一種樣式類,可以在文字中顯示圖片。
  • NSTextStorage,UITextView中的實際的文字封裝。(見參考中的UITextView文件)

表情與其標誌

首先需要明確的是,我們的自定義表情一定是有一一對應的“標誌”的,如“[/emoji_haha]”。
就是說,為了方便處理,方便在資料庫、網路傳輸中儲存、傳輸帶有表情圖片的文字,我們必須要為每種表情取特定的“名字”,資料庫中儲存的、網路傳輸的文字就只包含這些標誌名字就行,在顯示的時候做對應的替換。

如:

tutuge.meimageimage

對應的純文字就是:

tutuge.me[/emoji_1]

插入並顯示錶情圖片

插入表情很簡單,直接例項化NSTextAttachment類,將需要的表情的UIImage例項賦值給NSTextAttachment的image屬性,然後用“[NSAttributedString attributedStringWithAttachment:]

”方法例項化一個NSAttributedString的物件,插入到UITextView的textStorage對應的位置即可。

如下:

NSTextAttachment *emojiTextAttachment = [NSTextAttachment new];

//設定表情圖片
emojiTextAttachment.image = emojiImage;

//插入表情
[textView.textStorage insertAttributedString:[NSAttributedString attributedStringWithAttachment:emojiTextAttachment]
                                      atIndex:
textView.selectedRange.location];

這樣,就能在UITextView當前游標位置插入表情圖片了。

獲取帶有表情標誌的文字字串

難點

NSTextAttachment被插入到NSAttributedString中的時候,就被當成了一個字元處理!!!
就是說,只從UITextView的text中,是找不迴文本里面不同的表情所對應的標誌的!

解決點

  1. 我們要能遍歷出當前文字中所有的表情,也就是NSTextAttachment類。
  2. 我們要能知道遍歷出的表情,對應的標誌是什麼。

遍歷所有的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來的強大(自己也在學習中)~

如果有更好地辦法,一定要告訴我啊~~~

參考