編輯:關於Android編程
Android表情功能處理方案概述
1.原理和實現思路
2.表情圖片顯示
3.表情面板
4.表情的輸入框插入和刪除
5.表情添加腳本
Android中表情功能,一般都不是用ImageView去設置圖片實現的,表情一般會嵌套在文本之中,那麼如何實現呢,這裡就介紹一下其中的原理,此外還有相關功能的實現思路和具體代碼。
先看下良心動態圖
1.原理和思路
a.表情內容的數據格式
表情看上去是圖片,但是在數據傳輸的時候本質上是一個特殊文本;
比如QQ表情就是一個 "/表情字母"的結構,比如害羞的表情就是/hx,呲牙就是/cy...;
微博裡表情就是"[表情名字]"的接口,比如可愛的表情就是[可愛]等等...。
b.特殊文本顯示圖片的原理
需要用到安卓中的SpannableString拓展性字符串相關知識;
SpannableString可以讓一段字符串在顯示的時候,將其中某小段文字附著上其他內容;
附著的拓展內容可能是圖片,或者是文字格式,比如加粗斜體等。
下面稍微展開介紹下SpannableString,會的可以跳過
常用的拓展內容包含有
BackgroundColorSpan 背景色
ClickableSpan 文本可點擊,有點擊事件
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,再創建一個需要類型的Span對象,比如表情圖片就是ImageSpan,然後利用SpannableString的setSpan方法,將span對象設置在對應位置。
start就是需要附著的內容的開始位置
end是需要附著的內容的開始位置
flag標志位,這裡是最常用的EXCLUSIVE_EXCLUSIVE的表示span拓展文本不包含前後,
此外還有INCLUSIVE是包含的意思
舉例說明下,原文字是"文章作者是大帥比",那我創建個粗體拓展內容,並且要將其附著到作者二字上讓其變成粗體,那開始位置就是2,即第三個字;結束位置就是4,即第五個,然後按照"包頭不包尾"原則,包含第三個字不包含第五個字,即處理的就是第三四倆字"作者",flag我們將其設為EXCLUSIVE_INCLUSIVE即不包含前包含後。
那最終顯示的文字就是"文章作者是大帥比"
如果我們在附著內容及作者二字前面輸入內容時,由於是EXCLUSIVE不包含,所以不會跟著變化
"文章boredream作者是大帥比"
如果我們在附著內容及作者二字後面輸入內容時,由於是INCLUSIVE包含,新內容也會包含進效果
"文章作者boredream是大帥比"
c.特殊文字的匹配
知道要處理哪些特殊文本,怎麼處理,還有一步是怎麼把特殊文本從一段文字裡挑出來,即獲取到特殊本文的開始和結束位置,以及他的文字內容,這裡就要用到正則去進行匹配獲取了正則的規則就不細說了,介紹下表情這裡的正則匹配。
2.表情圖片顯示
文字附著表情圖片很簡單,用SpannableString中的ImageSpan,難點在於正則部分的獲取處理:
首先是正則的寫法,根據需要自行編寫規則,這裡以微博表情為例String regex = "\\[[\u4e00-\u9fa5\\w]+\\]";
簡單介紹下,最外面是方括號符號,要注意由於[]在正則中有特殊意義,所以需要用斜槓\轉義一下(\本身也需要轉義所以是倆\\),中間\u4e00-\u9fa5表示中文,\\w表示下劃線的任意單詞字符,+ 代表一個或者多個,那麼這段正則就代表,匹配方括號內有一或多個文字和單詞字符的文本。
然後去while循環匹配就可以了,用matcher.find獲取到匹配的開始位置,作為setSpan的start值,用matcher.group方法獲取到匹配規則的具體表情文字,end值則直接利用開始位置加上表情文字的長度即可。
貼上代碼
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(); // 利用表情名字獲取到對應的圖片 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; }
基本思路前面提過了,圖片處理的地方還要再說明下
表情如果直接獲取資源文件裡的圖片,可能會過大,所以方法參數裡傳入了需要顯示的文字控件,然後利用文字大小去將表情圖片再壓縮一下,其中,EmotionUtils類就不介紹了,裡面就是一個map集合,key為表情名字,value為表情圖片的resId,然後提供一個getImgByName的方法可以根據名字獲取圖片鍵值對需要一個個添加比較麻煩,我們會在最後介紹一個表情添加的腳本,方便快速導入圖片資源。
3.表情面板
結構就是ViewPager提供多頁滑動,每頁都是一個GridView顯示20個表情,末尾還有一個刪除按鈕;
ViewPager和GridView的基本使用方法就不介紹了,這裡說明下其中的特殊處理;
a.每個GridView的大小設置
GridView會顯示3行7列,共21個Item,為了讓Item能大小合適,最好的方法是利用動態計算的方式設置寬高,因為屏幕寬度各有不同,其他的一些大小計算也要注意用dp值轉換下獲取對應的px再使用,保證適配問題。
思路是獲取屏幕寬度,減去間隙距離,然後除以7算出每個Item需要的寬度,然後再乘以3加上需要的間隙,算出表情面板的高度,利用算出來的值去創建設置面板大小。
b.需要多少個GridView
一共有多少頁呢,雖然表情大部分情況下總數是固定的,但是最好還是根據代碼的方式算出來需要多少頁,而非直接人去目測計算要多少個GridView。
思路是for循環全部的圖片名字,這裡利用map.keySet獲取全部的鍵集合,每次循環都把圖片名添加到一個集合中,然後進行判斷,如果滿20個了就作為一組表情,新建一個GridView設置上去,最後把所有表情生成的一個個GridView放到一個總view集合中,利用ViewPager顯示。
c.GridView末尾刪除鍵處理
適配器和點擊事件中,都利用position判斷,如果是最後一個就進行特殊的顯示和點擊處理。
這幾部分的代碼比較亂,但是沒有什麼新知識點,都是一些邏輯方面的內容,就不貼出來了。
4.表情的輸入框插入和刪除
實質上還是對表情對應的文本數據進行操作,這裡最要注意的地方是輸入框中的光標問題,輸入框其實也是TextView的一種,顯示和之前介紹的方法一樣,但是動態的添加和刪除就需要注意處理位置的問題了。
a.手動設置光標
新添加一個表情,應該是在輸入框中當前光標的位置插入圖片,所以首先要知道光標的位置獲取這裡可以用et.setSelectionStart方法;
還有一點,添加完表情以後,光標應該更新到新添加內容後面,而設置光標位置就要用et.setSelection(position)方法。
b.調用系統按鈕事件自動處理
刪除就比較簡單了,這裡直接調用系統的 Delete 按鈕事件即可,讓某個控件調用按鈕事件的方法為et.displatchKeyEvent(new KeyEvent(action, code));其中action就是動作,用ACTION_DOWN按下動作就可以了,而code為按鈕事件碼,刪除對應的就是KEYCODE_DEL。
5.表情添加腳本
以上,知識點就全部介紹完畢了,最後是福利時間。
表情少則幾十,多則甚至上百~ 一個一個的根據名字設置對應表情鍵值對會各種痛苦,這裡推薦編寫腳本進行處理,也就是寫段功能自動的生成所需代碼;
這段就比較靈活了,需要根據不同需要編寫腳本,所以主要是提供個思路然後以微博為例編寫代碼;
微博中表情是"[表情文字]",而表情圖片名字則是"d_表情拼音"(此外還有其他的名字樣式,比如h_或者emoji_等等,暫時不管,處理原理都差不多);
這裡要先說明一下前提,必須要按照一定規則來才能進行這種半自動化的處理,如果表情干脆名字就是瞎起的,那就沒轍了,如果是公司自己做應用的話,一定要讓美工切圖後導出的圖片文件名按照套路出牌;
新浪微博中d_表情拼音這裡就都是中文對應的拼音而非英文,且中文都是和[表情文字]一致的,比如害羞表情的文字就是[害羞],而圖片名字就是d_haixiu。
那微博這裡處理就可以按照套路來了
1) 打開微博原版客戶端,把所有表情全部選中,然後發出來
2) 在日志裡獲取到這段圖片對應的文字數據
3) 用表情文字規則對這段文字進行循環匹配
4) 每次循環的時候都,把匹配的表情名字轉為拼音(pinyin4j等工具)
5) 把表情文字轉成的拼音再拼成圖片資源的名字(微博這裡就是加個"d_"前綴)
6) 拼接map.put的代碼
7) 循環完成後,打印出來全部的map.put代碼,然後復制到我們的表情工具類中使用
貼上代碼,腳本直接新建一個java的項目放在main函數裡運行就可以了
public static void weiboEmoji() { StringBuilder sb = new StringBuilder(); String names = "[羞羞哒甜馨][萌神奧莉][帶著微博去旅行][愛紅包][拍照][馬到成功]→_→[呵呵][嘻嘻][哈哈][愛你][挖鼻屎][吃驚][暈][淚][饞嘴][抓狂][哼][可愛][怒][汗][害羞][睡覺][錢][偷笑][笑cry][doge][喵喵][酷][衰][閉嘴][鄙視][花心][鼓掌][悲傷][思考][生病][親親][怒罵][太開心]" + "[懶得理你][右哼哼][左哼哼][噓][委屈][吐][可憐][打哈氣][擠眼][失望][頂][疑問][困][感冒][拜拜][黑線][陰險][打臉][傻眼][互粉][心][傷心][豬頭][熊貓][兔子]" ; 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()); }
運行結果,從控制台復制代碼粘貼到項目裡的工具類中即可
可能有的表情文件名就是不按套路來,比如新浪微博這裡的笑哭的表情,文字就是[笑cry],而圖片文件名是d_xiaoku,那麼也沒關系,你復制到項目中,如果圖片資源匹配不上的話也會報錯提示,進行對應修改即可。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
shape的屬性有:- corners–圓角- padding–內邊距- size(height、width)–設置寬高- strok
一、概述 對於加載圖片,大家都不陌生,一般為了盡可能避免OOM都會按照如下做法: 對於圖片顯示:根據需要顯示圖片控件的大小對圖片進行壓縮顯示。如果圖片數量非常多:則會使
首先我們先看下效果圖實現思路這是兩張前後對比圖,右邊第二張圖裡面的已搶光標簽圖片當已經沒有商品的時候就會顯示了,在每個圖片的中心位置,第一想法是在ImageView的外層
前言因為工作需要可能要用到JNI開發,本篇文章就分享一下我在這方面的實踐,以前我們使用Eclipse做NDK開發,非常麻煩,需要配cygwin的編譯環境,後面NDK功能完