亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS中表情鍵盤的完整實現方法詳解

2020-07-26 02:27:01
字體:
來源:轉載
供稿:網友

前言

最近在公司做了個表情鍵盤的需求,這個需求的技術難度不會很大,比較偏向業務。但是要把用戶體驗做的好也是不容易的,其中有幾個點需要特別注意。話不多說,下面開始正文(注:本文對應的Demo放在Github上:https://github.com/VernonVan/PPStickerKeyboard (本地上傳) )。

市面上的表情鍵盤的分析

首先來看一下市面上主要的幾個APP上的表情鍵盤,平時使用的時候不會去關注細節,這次特意去使用了表情鍵盤,發現各個APP的體驗還是有優有劣的。

首先是QQ和微信,這兩者差不多,切換到表情鍵盤的時候都是沒有光標的,這樣的用戶體驗是非常不好的,沒有辦法在輸入表情的時候框選區域,也不能拖動光標進行特定位置的復制黏貼刪除等操作,微信甚至在輸入框里顯示的都不是點擊的表情圖片,而是文字描述。

微信QQ表情鍵盤.JPG

接下來看一下微博國際版,國際版調起表情鍵盤時是有光標的,是一個"真正的"鍵盤,但是想要拖拽光標的時候,很大概率上會觸發到保存圖片的行為(如下圖所示),導致根本沒辦法拖動光標。


微博國際版誤觸.JPG

同時微博國際版輸入框表情黏貼后的光標定位是錯誤的,如下圖,開始時光標是在第4個表情后面,然后復制狗頭+害羞兩個表情黏貼到光標后,光標還是在第4個表情后,同時黏貼的表情前后都莫名多了空格。


微博國際版黏貼.JPG

最后是微博,微博客戶端的表情鍵盤的體驗是非常好的,上面說到的問題都不存在,而且表情鍵盤的刪除按鈕還能長按刪除輸入框的內容。


微博表情鍵盤.jpg

表情鍵盤的實現

實現效果

主要實現了以下幾個功能

  • 能輸入表情,有光標,支持復制黏貼刪除表情等
  • 長按預覽表情
  • 刪除表情、長按連續刪除表情
  • 適配 iPhone X


演示.GIF

基本思路

首先,表情包的圖片是用bundle的形式組織的,用PPSticker類表征一套表情包,用PPEmoji類表征某一個表情,用一個plist作為配置文件,存儲表情包的信息。

表情的組織.jpg

PPStickerDataManager類主要負責數據部分,用單例的形式,這樣可以在初始化的時候只會讀取一次plist文件中的所有表情信息;同時我們把輸入框內容發到服務端以及從服務端請求到的都是純文本的,比如會把 "笑死了🤣" 轉成 "笑死了[笑哭]" 這樣的純文本,而不是直接把表情圖片直接發到服務端,也就是說項目中有大量的地方會有把文本->表情的操作,所以PPStickerDataManager類也提供匹配某段純文本中的表情,并把文本替換為圖片的功能,PPStickerDataManager類的頭文件如下:

@interface PPStickerDataManager : NSObject+ (instancetype)sharedInstance;/// 所有的表情包@property (nonatomic, strong, readonly) NSArray<PPSticker *> *allStickers;/* 匹配給定attributedString中的所有emoji,如果匹配到的emoji有本地圖片的話會直接換成本地的圖片** @param attributedString 可能包含表情包的attributedString* @param font 表情圖片的對齊字體大小*/- (void)replaceEmojiForAttributedString:(NSMutableAttributedString *)attributedString font:(UIFont *)font;@end

"真正的"鍵盤

真正的鍵盤也就是說調起表情鍵盤時輸入框是有光標的,能進行拖拽光標、選中區域等的操作,這樣的體驗才是與系統鍵盤一致的。其實系統已經提供好了接口給我們直接使用,UITextView和UITextField都有的inputView和inputAccessoryView就是用來實現自定義鍵盤的,這兩個屬性的定義如下:

// Presented when object becomes first responder. If set to nil, reverts to following responder chain. If// set while first responder, will not take effect until reloadInputViews is called.@property (nullable, readwrite, strong) UIView *inputView;  @property (nullable, readwrite, strong) UIView *inputAccessoryView;

同時系統鍵盤在 設置->聲音->按鍵音 選項打開且手機非靜音狀態下輸入是有按鍵的聲音的,這個按鍵音也是可以支持的,只要自定義鍵盤類遵循UIInputViewAudioFeedback協議,同時實現 enableInputClicksWhenVisible方法并返回YES,這樣就可以在點擊表情的時候調用[[UIDevice currentDevice] playInputClick]方法發出按鍵音了,詳情請查看蘋果的官方文檔。

下面是Demo中鍵盤切換方法的實現:

- (void)changeKeyboardTo:(PPKeyboardType)toType{ switch (toType) { case PPKeyboardTypeSystem:  self.textView.inputView = nil; // 切換到系統鍵盤  [self.textView reloadInputViews]; // 調用reloadInputViews方法會立刻進行鍵盤的切換  break; case PPKeyboardTypeSticker:    self.textView.inputView = self.stickerKeyboard; // 切換到自定義的表情鍵盤  [self.textView reloadInputViews];  break; default:  break; }}

去除表情的拖拽交互

在iOS11上,UITextView上的NSTextAttachment(表情)默認可以進行拖拽交互,但是卻導致拖動光標時很容易觸發這個交互(圖示可以查看上面說到的微博國際版中的誤觸)。一番查找之后才找到一個比較隱蔽的屬性:textDragInteraction,直接設置為NO就能禁止掉NSTextAttachment的拖拽交互。

if (@available(iOS 11.0, *)) { // 只在iOS11及以上才有這個屬性 _textView.textDragInteraction.enabled = NO;}

與服務端的交互

我們在輸入框中輸入的內容與服務端進行交互的時候都是用純文本的,比如會把 "笑死了🤣" 轉成 "笑死了[笑哭]" 這樣的純文本發到服務端,而不是直接發表情圖片,向服務端請求內容的時候也是傳回 "笑死了[笑哭]",然后客戶端再根據正則匹配找出表情替換成對應的表情圖片,然后顯示到頁面上。具體過程可以看下圖:


與服務端的交互.png

也就是說,我們設置到輸入框的NSAttributedString中的每一個NSTextAttachment都有一個"隱藏的"屬性―表情的文本描述,這里對NSAttributedString進行拓展就能實現。pp_setTextBackedString可以對NSAttributedString的指定range設置一個PPTextBackedString類型的屬性,而pp_plainTextForRange能拿到NSAttributedString指定range的純文本。具體實現如下:

@implementation NSAttributedString (PPAddition)- (NSString *)pp_plainTextForRange:(NSRange)range{ if (range.location == NSNotFound || range.length == NSNotFound) { return nil; } NSMutableString *result = [[NSMutableString alloc] init]; if (range.length == 0) { return result; } NSString *string = self.string; [self enumerateAttribute:PPTextBackedStringAttributeName inRange:range options:kNilOptions usingBlock:^(id value, NSRange range, BOOL *stop) { PPTextBackedString *backed = value; if (backed && backed.string) {  [result appendString:backed.string]; } else {  [result appendString:[string substringWithRange:range]]; } }]; return result;}@end@implementation NSMutableAttributedString (PPAddition)- (void)pp_setTextBackedString:(PPTextBackedString *)textBackedString range:(NSRange)range{ if (textBackedString && ![NSNull isEqual:textBackedString]) { [self addAttribute:PPTextBackedStringAttributeName value:textBackedString range:range]; } else { [self removeAttribute:PPTextBackedStringAttributeName range:range]; }}@end

靈活的光標

表情功能,UITextView都是用NSAttributedString進行賦值的,并且我們底層其實還是用上面說到的純文本進行實現的,那么把 [笑死] 轉成 🤣 就會從4個字符變成1個字符,這里是有差值的,如果不處理的話就會出現上面提到的微博國際版中復制黏貼輸入框的表情會導致光標位置不對,甚至莫名其妙多出前后空格的問題。為了精準的定位光標,我們需要自行處理好這些問題。

這里自己繼承并實現了UITextView的子類PPStickerTextView,在這個類中重載復制、黏貼、剪切等操作,分別對應的方法如下:

- (void)cut:(id)sender; // 剪切- (void)copy:(id)sender; // 復制- (void)paste:(id)sender; // 黏貼

下面以剪切方法舉例,看看怎么處理光標的問題,需要注意的地方請看對應的注釋:

- (void)cut:(id)sender{ // 1.從textView中拿到對應的純文本,比如:笑死了[笑死] NSString *string = [self.attributedText pp_plainTextForRange:self.selectedRange]; if (string.length) { // 2. 將純文本寫入到剪貼板中 [UIPasteboard generalPasteboard].string = string; // 3. 記住當前的光標位置 NSRange selectedRange = self.selectedRange; NSMutableAttributedString *attributeContent = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; // 4. 將檢測到是表情的文本替換成對應的圖片 [attributeContent replaceCharactersInRange:self.selectedRange withString:@""]; self.attributedText = attributeContent;  // 5. 重新設置光標 self.selectedRange = NSMakeRange(selectedRange.location, 0); }}

技術點的分析就是以上這些,詳細的代碼可以到Github上clone下來查看:https://github.com/VernonVan/PPStickerKeyboard (本地上傳)

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人激情图片网| 欧美三级xxx| 欧美性xxxxx极品| 国产精品九九九| 亚洲欧美综合精品久久成人| 日韩欧美精品中文字幕| 国产91精品黑色丝袜高跟鞋| 国产91精品久| 国产精品揄拍500视频| 久久亚洲国产精品成人av秋霞| 国产精品一区二区久久国产| 国产亚洲欧美aaaa| 久久九九热免费视频| 亚洲午夜未删减在线观看| 在线观看视频亚洲| 久久久久久国产三级电影| 91精品国产91久久久久久最新| 亚洲欧美制服第一页| 国产精品网红直播| 狠狠躁夜夜躁人人爽超碰91| 亚洲综合色激情五月| 久精品免费视频| 日韩中文字幕在线看| 国产69精品久久久久9999| 欧美电影免费观看| 人九九综合九九宗合| 欧美在线一级视频| 精品久久久999| 一本久久综合亚洲鲁鲁| 国产噜噜噜噜久久久久久久久| 国模吧一区二区三区| 欧美日韩国产丝袜美女| 亚洲免费电影在线观看| 一本一道久久a久久精品逆3p| 亚洲护士老师的毛茸茸最新章节| 91精品视频免费观看| 欧洲成人免费视频| 欧美精品在线免费播放| 91免费国产视频| 成人精品福利视频| 久久国产精品亚洲| 亚洲国产欧美久久| 国产欧美一区二区三区四区| 久久视频国产精品免费视频在线| 久久天天躁狠狠躁夜夜躁| 国产精品视频在线观看| 欧美日韩成人网| 亚洲精品999| 国产成人精品日本亚洲专区61| 欧美精品日韩三级| 国产视频精品va久久久久久| 国产视频亚洲精品| 久久久久日韩精品久久久男男| 欧美有码在线视频| 国产日韩在线看片| 国产丝袜精品第一页| 精品视频在线播放色网色视频| 亚洲最新av在线| 欧美电影免费观看高清| 欧美精品videossex88| 国产视频精品免费播放| 456亚洲影院| 在线精品高清中文字幕| 色午夜这里只有精品| 日韩高清免费观看| 国产精品久久久久久久久久新婚| 91精品国产自产在线观看永久| 91色琪琪电影亚洲精品久久| 精品香蕉一区二区三区| 成人久久一区二区| 日韩电影中文字幕一区| 国产精品久久久久久久7电影| 亚洲永久在线观看| 欧美黑人性生活视频| 精品国产91乱高清在线观看| 国产一区二区久久精品| 亚洲a成v人在线观看| 日韩av成人在线| 欧美老少配视频| www国产精品com| 国产精品自拍小视频| 日韩免费观看视频| 亚洲欧美日韩一区二区在线| 国产精品久久久久久超碰| 大桥未久av一区二区三区| 国产精品久久久一区| 911国产网站尤物在线观看| 欧美午夜视频一区二区| 97在线日本国产| 亚洲自拍偷拍网址| 国产欧美一区二区三区久久人妖| 欧美日韩国产黄| 精品一区二区电影| 日本不卡免费高清视频| 这里精品视频免费| 欧美成人精品一区| 国产亚洲精品久久久优势| 亚洲人午夜色婷婷| 亚洲欧美日韩精品| 亚洲国产福利在线| 欧美视频在线观看免费网址| 欧美性一区二区三区| 国产精品91免费在线| 在线电影中文日韩| 亚洲精品av在线播放| 欧美一性一乱一交一视频| 亚洲天堂精品在线| 国产97免费视| 中文字幕一精品亚洲无线一区| 日韩欧美在线免费观看| 国产成人精品a视频一区www| 欧美孕妇与黑人孕交| 国产精欧美一区二区三区| 亚洲第一福利在线观看| 国内精品久久久久久影视8| 日韩中文字幕在线视频播放| 8050国产精品久久久久久| 欧美日韩亚洲激情| 国产在线观看一区二区三区| 精品久久久久久中文字幕| 色播久久人人爽人人爽人人片视av| 久久综合88中文色鬼| 日韩高清中文字幕| 成人精品视频在线| 亚洲bt欧美bt日本bt| 久久久久久97| 久久久亚洲天堂| 亚洲香蕉av在线一区二区三区| 黑人极品videos精品欧美裸| 亚洲欧美激情在线视频| 久久久久国产一区二区三区| 欧美大片免费观看| 成人欧美一区二区三区在线湿哒哒| 精品久久久精品| 国产精品影院在线观看| 日韩在线观看免费av| 久久久久五月天| 欧美日在线观看| 日韩日本欧美亚洲| 91色精品视频在线| 国产男人精品视频| 日韩电影免费观看在线| 在线精品播放av| 欧美日韩国产精品专区| 欧美日韩综合视频| 45www国产精品网站| 91久久精品国产91性色| 97国产在线观看| 久久网福利资源网站| 欧美肥臀大乳一区二区免费视频| 欧美精品成人在线| 青草青草久热精品视频在线网站| 久久久久中文字幕2018| 夜夜嗨av一区二区三区免费区| 91久久精品国产91性色| 日本乱人伦a精品| 国产69久久精品成人| 国产午夜精品全部视频在线播放| 久久天堂电影网| 欧美专区福利在线| 亚洲美女性生活视频| 久久影视免费观看| 午夜精品在线视频| 这里只有精品在线播放|