完整的Android表情功能處理方案
Android表情功能處理方案概述
1.原理和實(shí)現(xiàn)思路
2.表情圖片顯示
3.表情面板
4.表情的輸入框插入和刪除
5.表情添加腳本
Android中表情功能,一般都不是用ImageView去設(shè)置圖片實(shí)現(xiàn)的,表情一般會(huì)嵌套在文本之中,那么如何實(shí)現(xiàn)呢,這里就介紹一下其中的原理,此外還有相關(guān)功能的實(shí)現(xiàn)思路和具體代碼。
先看下良心動(dòng)態(tài)圖
1.原理和思路
a.表情內(nèi)容的數(shù)據(jù)格式
表情看上去是圖片,但是在數(shù)據(jù)傳輸?shù)臅r(shí)候本質(zhì)上是一個(gè)特殊文本;
比如QQ表情就是一個(gè) "/表情字母"的結(jié)構(gòu),比如害羞的表情就是/hx,呲牙就是/cy...;
微博里表情就是"[表情名字]"的接口,比如可愛的表情就是[可愛]等等...。
b.特殊文本顯示圖片的原理
需要用到安卓中的SpannableString拓展性字符串相關(guān)知識(shí);
SpannableString可以讓一段字符串在顯示的時(shí)候,將其中某小段文字附著上其他內(nèi)容;
附著的拓展內(nèi)容可能是圖片,或者是文字格式,比如加粗斜體等。
下面稍微展開介紹下SpannableString,會(huì)的可以跳過
常用的拓展內(nèi)容包含有
BackgroundColorSpan 背景色
ClickableSpan 文本可點(diǎn)擊,有點(diǎn)擊事件
UnderlineSpan 下劃線
ImageSpan 圖片
StyleSpan 字體樣式:粗體、斜體等
URLSpan 文本超鏈接
此外還有刪除線,縮放大小等不同樣式的拓展
用法
SpannableString spannableString = new SpannableString(source); ImageSpan span = new ImageSpan(context, bitmap); spannableString.setSpan(span, start, start + emojiStr.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
解釋下用法
首先將原String文字包裝成拓展性文字SpannableString,再創(chuàng)建一個(gè)需要類型的Span對(duì)象,比如表情圖片就是ImageSpan,然后利用SpannableString的setSpan方法,將span對(duì)象設(shè)置在對(duì)應(yīng)位置。
start就是需要附著的內(nèi)容的開始位置
end是需要附著的內(nèi)容的開始位置
flag標(biāo)志位,這里是最常用的EXCLUSIVE_EXCLUSIVE的表示span拓展文本不包含前后,
此外還有INCLUSIVE是包含的意思
舉例說明下,原文字是"文章作者是大帥比",那我創(chuàng)建個(gè)粗體拓展內(nèi)容,并且要將其附著到作者二字上讓其變成粗體,那開始位置就是2,即第三個(gè)字;結(jié)束位置就是4,即第五個(gè),然后按照"包頭不包尾"原則,包含第三個(gè)字不包含第五個(gè)字,即處理的就是第三四倆字"作者",flag我們將其設(shè)為EXCLUSIVE_INCLUSIVE即不包含前包含后。
那最終顯示的文字就是"文章作者是大帥比"
如果我們?cè)诟街鴥?nèi)容及作者二字前面輸入內(nèi)容時(shí),由于是EXCLUSIVE不包含,所以不會(huì)跟著變化
"文章boredream作者是大帥比"
如果我們?cè)诟街鴥?nèi)容及作者二字后面輸入內(nèi)容時(shí),由于是INCLUSIVE包含,新內(nèi)容也會(huì)包含進(jìn)效果
"文章作者boredream是大帥比"
c.特殊文字的匹配
知道要處理哪些特殊文本,怎么處理,還有一步是怎么把特殊文本從一段文字里挑出來,即獲取到特殊本文的開始和結(jié)束位置,以及他的文字內(nèi)容,這里就要用到正則去進(jìn)行匹配獲取了正則的規(guī)則就不細(xì)說了,介紹下表情這里的正則匹配。
2.表情圖片顯示
文字附著表情圖片很簡(jiǎn)單,用SpannableString中的ImageSpan,難點(diǎn)在于正則部分的獲取處理:
首先是正則的寫法,根據(jù)需要自行編寫規(guī)則,這里以微博表情為例String regex = "\\[[\u4e00-\u9fa5\\w]+\\]";
簡(jiǎn)單介紹下,最外面是方括號(hào)符號(hào),要注意由于[]在正則中有特殊意義,所以需要用斜杠\轉(zhuǎn)義一下(\本身也需要轉(zhuǎn)義所以是倆\\),中間\u4e00-\u9fa5表示中文,\\w表示下劃線的任意單詞字符,+ 代表一個(gè)或者多個(gè),那么這段正則就代表,匹配方括號(hào)內(nèi)有一或多個(gè)文字和單詞字符的文本。
然后去while循環(huán)匹配就可以了,用matcher.find獲取到匹配的開始位置,作為setSpan的start值,用matcher.group方法獲取到匹配規(guī)則的具體表情文字,end值則直接利用開始位置加上表情文字的長(zhǎng)度即可。
貼上代碼
public static SpannableString getEmotionContent( final Context context, final TextView tv, String source) { SpannableString spannableString = new SpannableString(source); Resources res = context.getResources(); String regexEmotion = "\\[([\u4e00-\u9fa5\\w])+\\]" ; Pattern patternEmotion = Pattern. compile(regexEmotion); Matcher matcherEmotion = patternEmotion.matcher(spannableString); while (matcherEmotion.find()) { // 獲取匹配到的具體字符 String key = matcherEmotion.group(); // 匹配字符串的開始位置 int start = matcherEmotion.start(); // 利用表情名字獲取到對(duì)應(yīng)的圖片 Integer imgRes = EmotionUtils. getImgByName(key); if (imgRes != null) { // 壓縮表情圖片 int size = ( int) tv.getTextSize(); Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes); Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true); ImageSpan span = new ImageSpan(context, scaleBitmap); spannableString.setSpan(span, start, start + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE ); } } return spannableString; }
基本思路前面提過了,圖片處理的地方還要再說明下
表情如果直接獲取資源文件里的圖片,可能會(huì)過大,所以方法參數(shù)里傳入了需要顯示的文字控件,然后利用文字大小去將表情圖片再壓縮一下,其中,EmotionUtils類就不介紹了,里面就是一個(gè)map集合,key為表情名字,value為表情圖片的resId,然后提供一個(gè)getImgByName的方法可以根據(jù)名字獲取圖片鍵值對(duì)需要一個(gè)個(gè)添加比較麻煩,我們會(huì)在最后介紹一個(gè)表情添加的腳本,方便快速導(dǎo)入圖片資源。
3.表情面板
結(jié)構(gòu)就是ViewPager提供多頁滑動(dòng),每頁都是一個(gè)GridView顯示20個(gè)表情,末尾還有一個(gè)刪除按鈕;
ViewPager和GridView的基本使用方法就不介紹了,這里說明下其中的特殊處理;
a.每個(gè)GridView的大小設(shè)置
GridView會(huì)顯示3行7列,共21個(gè)Item,為了讓Item能大小合適,最好的方法是利用動(dòng)態(tài)計(jì)算的方式設(shè)置寬高,因?yàn)槠聊粚挾雀饔胁煌?,其他的一些大小?jì)算也要注意用dp值轉(zhuǎn)換下獲取對(duì)應(yīng)的px再使用,保證適配問題。
思路是獲取屏幕寬度,減去間隙距離,然后除以7算出每個(gè)Item需要的寬度,然后再乘以3加上需要的間隙,算出表情面板的高度,利用算出來的值去創(chuàng)建設(shè)置面板大小。
b.需要多少個(gè)GridView
一共有多少頁呢,雖然表情大部分情況下總數(shù)是固定的,但是最好還是根據(jù)代碼的方式算出來需要多少頁,而非直接人去目測(cè)計(jì)算要多少個(gè)GridView。
思路是for循環(huán)全部的圖片名字,這里利用map.keySet獲取全部的鍵集合,每次循環(huán)都把圖片名添加到一個(gè)集合中,然后進(jìn)行判斷,如果滿20個(gè)了就作為一組表情,新建一個(gè)GridView設(shè)置上去,最后把所有表情生成的一個(gè)個(gè)GridView放到一個(gè)總view集合中,利用ViewPager顯示。
c.GridView末尾刪除鍵處理
適配器和點(diǎn)擊事件中,都利用position判斷,如果是最后一個(gè)就進(jìn)行特殊的顯示和點(diǎn)擊處理。
這幾部分的代碼比較亂,但是沒有什么新知識(shí)點(diǎn),都是一些邏輯方面的內(nèi)容,就不貼出來了。
4.表情的輸入框插入和刪除
實(shí)質(zhì)上還是對(duì)表情對(duì)應(yīng)的文本數(shù)據(jù)進(jìn)行操作,這里最要注意的地方是輸入框中的光標(biāo)問題,輸入框其實(shí)也是TextView的一種,顯示和之前介紹的方法一樣,但是動(dòng)態(tài)的添加和刪除就需要注意處理位置的問題了。
a.手動(dòng)設(shè)置光標(biāo)
新添加一個(gè)表情,應(yīng)該是在輸入框中當(dāng)前光標(biāo)的位置插入圖片,所以首先要知道光標(biāo)的位置獲取這里可以用et.setSelectionStart方法;
還有一點(diǎn),添加完表情以后,光標(biāo)應(yīng)該更新到新添加內(nèi)容后面,而設(shè)置光標(biāo)位置就要用et.setSelection(position)方法。
b.調(diào)用系統(tǒng)按鈕事件自動(dòng)處理
刪除就比較簡(jiǎn)單了,這里直接調(diào)用系統(tǒng)的 Delete 按鈕事件即可,讓某個(gè)控件調(diào)用按鈕事件的方法為et.displatchKeyEvent(new KeyEvent(action, code));其中action就是動(dòng)作,用ACTION_DOWN按下動(dòng)作就可以了,而code為按鈕事件碼,刪除對(duì)應(yīng)的就是KEYCODE_DEL。
5.表情添加腳本
以上,知識(shí)點(diǎn)就全部介紹完畢了,最后是福利時(shí)間。
表情少則幾十,多則甚至上百~ 一個(gè)一個(gè)的根據(jù)名字設(shè)置對(duì)應(yīng)表情鍵值對(duì)會(huì)各種痛苦,這里推薦編寫腳本進(jìn)行處理,也就是寫段功能自動(dòng)的生成所需代碼;
這段就比較靈活了,需要根據(jù)不同需要編寫腳本,所以主要是提供個(gè)思路然后以微博為例編寫代碼;
微博中表情是"[表情文字]",而表情圖片名字則是"d_表情拼音"(此外還有其他的名字樣式,比如h_或者emoji_等等,暫時(shí)不管,處理原理都差不多);
這里要先說明一下前提,必須要按照一定規(guī)則來才能進(jìn)行這種半自動(dòng)化的處理,如果表情干脆名字就是瞎起的,那就沒轍了,如果是公司自己做應(yīng)用的話,一定要讓美工切圖后導(dǎo)出的圖片文件名按照套路出牌;
新浪微博中d_表情拼音這里就都是中文對(duì)應(yīng)的拼音而非英文,且中文都是和[表情文字]一致的,比如害羞表情的文字就是[害羞],而圖片名字就是d_haixiu。
那微博這里處理就可以按照套路來了
1) 打開微博原版客戶端,把所有表情全部選中,然后發(fā)出來
2) 在日志里獲取到這段圖片對(duì)應(yīng)的文字?jǐn)?shù)據(jù)
3) 用表情文字規(guī)則對(duì)這段文字進(jìn)行循環(huán)匹配
4) 每次循環(huán)的時(shí)候都,把匹配的表情名字轉(zhuǎn)為拼音(pinyin4j等工具)
5) 把表情文字轉(zhuǎn)成的拼音再拼成圖片資源的名字(微博這里就是加個(gè)"d_"前綴)
6) 拼接map.put的代碼
7) 循環(huán)完成后,打印出來全部的map.put代碼,然后復(fù)制到我們的表情工具類中使用
貼上代碼,腳本直接新建一個(gè)java的項(xiàng)目放在main函數(shù)里運(yùn)行就可以了
public static void weiboEmoji() { StringBuilder sb = new StringBuilder(); String names = "[羞羞噠甜馨][萌神奧莉][帶著微博去旅行][愛紅包][拍照][馬到成功]→_→[呵呵][嘻嘻][哈哈][愛你][挖鼻屎][吃驚][暈][淚][饞嘴][抓狂][哼][可愛][怒][汗][害羞][睡覺][錢][偷笑][笑cry][doge][喵喵][酷][衰][閉嘴][鄙視][花心][鼓掌][悲傷][思考][生病][親親][怒罵][太開心]" + "[懶得理你][右哼哼][左哼哼][噓][委屈][吐][可憐][打哈氣][擠眼][失望][頂][疑問][困][感冒][拜拜][黑線][陰險(xiǎn)][打臉][傻眼][互粉][心][傷心][豬頭][熊貓][兔子]" ; String regexEmoji = "\\[([\u4e00-\u9fa5a-zA-Z0-9])+\\]" ; Pattern patternEmoji = Pattern. compile(regexEmoji); Matcher matcherEmoji = patternEmoji.matcher(names); CharacterParser parser = CharacterParser. getInstance(); while (matcherEmoji.find()) { // 如果可以匹配到 String key = matcherEmoji.group(); // 獲取匹配到的具體字符 String pinyinName = "d_" + parser.getSpelling(key).replace("[" , "" ).replace("]" , "" ); sb.append( "emojiMap.put(\"" + key + "\", R.drawable." + pinyinName + ");\n" ); } System. out.println(sb.toString()); }
運(yùn)行結(jié)果,從控制臺(tái)復(fù)制代碼粘貼到項(xiàng)目里的工具類中即可
可能有的表情文件名就是不按套路來,比如新浪微博這里的笑哭的表情,文字就是[笑cry],而圖片文件名是d_xiaoku,那么也沒關(guān)系,你復(fù)制到項(xiàng)目中,如果圖片資源匹配不上的話也會(huì)報(bào)錯(cuò)提示,進(jìn)行對(duì)應(yīng)修改即可。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于Android開發(fā)支持表情的實(shí)現(xiàn)詳解
- Android開發(fā)技巧之像QQ一樣輸入文字和表情圖像
- Android自帶emoji表情的使用方法詳解
- Android編程實(shí)現(xiàn)QQ表情的發(fā)送和接收完整實(shí)例(附源碼)
- Android編程開發(fā)實(shí)現(xiàn)TextView顯示表情圖像和文字的方法
- 詳解Android過濾emoji表情正則表達(dá)式
- android高仿微信表情輸入與鍵盤輸入代碼(詳細(xì)實(shí)現(xiàn)分析)
- Android EdText編輯框禁止輸入表情符號(hào)(使用正則表達(dá)式)
- Android輸入框添加emoje表情圖標(biāo)的實(shí)現(xiàn)代碼
- Android實(shí)現(xiàn)表情功能
相關(guān)文章
Android九宮格手勢(shì)密碼代碼設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了Android九宮格手勢(shì)密碼的代碼設(shè)計(jì)思路,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Android開源項(xiàng)目PullToRefresh下拉刷新功能詳解
這篇文章主要為大家詳細(xì)介紹了Android開源項(xiàng)目PullToRefresh下拉刷新功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Android列表控件Spinner簡(jiǎn)單用法示例
這篇文章主要介紹了Android列表控件Spinner簡(jiǎn)單用法,結(jié)合實(shí)例形式分析了Android列表控件Spinner的布局與功能實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-12-12android 獲取手機(jī)GSM/CDMA信號(hào)信息,并獲得基站信息的方法
下面小編就為大家?guī)硪黄猘ndroid 獲取手機(jī)GSM/CDMA信號(hào)信息,并獲得基站信息的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11android RecycleView實(shí)現(xiàn)多級(jí)樹形列表
這篇文章主要為大家詳細(xì)介紹了android RecycleView實(shí)現(xiàn)多級(jí)樹形列表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05Android ListView滑動(dòng)刪除操作(SwipeListView)
這篇文章主要為大家詳細(xì)介紹了Android ListView滑動(dòng)刪除操作,主要是學(xué)習(xí)SwipeListView開源框架。感興趣的小伙伴們可以參考一下2016-08-08Android利用MediaRecorder實(shí)現(xiàn)錄音功能
這篇文章主要為大家詳細(xì)介紹了Android利用MediaRecorder實(shí)現(xiàn)錄音功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03