Android輸入框添加emoje表情圖標(biāo)的實(shí)現(xiàn)代碼
前言
再次寫(xiě)聊天的時(shí)候才發(fā)現(xiàn),代碼積累是一件非常重要的事情,就如這篇博客的意圖其實(shí)就是代碼積累的目的,其實(shí)沒(méi)什么難度,但是一件很瑣碎的事情真的也需要時(shí)間去完成和調(diào)試,所以,獲取你在寫(xiě)一個(gè)功能的時(shí)候會(huì)覺(jué)得并沒(méi)有多難,但是如果可以最好把代碼整理/積累下來(lái)。
demo描述

demo的功能其實(shí)就是仿照微信的 聊天 emoje 選擇,采用了 viewpager+gridView 的方案,不過(guò)有空我會(huì)補(bǔ)上 recyclerView 的方案,目前還是先把功能實(shí)現(xiàn)了再說(shuō)。另外在 TextView 和 EditText 中添加 emoje ,可以看看這篇博客:Android中使用TextView及EditText來(lái)實(shí)現(xiàn)表情圖標(biāo)的顯示及插入功能 ,這篇博客中介紹了兩種方法:
方法一:使用Html.fromHtml解析, 方法二:使用Bitmap直接畫(huà)出來(lái),我采用了第二種方法,使用bitmap畫(huà)出來(lái)。
Read the fucking code
思路:既然是 viewpager + gridview 那么,先從大方向入手,完成 viewpager,再去完成 gridview。PS:代碼里面使用了 RxJava、lambda、ButterKnife、EventBus、Glide。
這里將整個(gè)底部布局寫(xiě)成了一個(gè)組合的ViewGroup – ChatBottomBar,先從布局開(kāi)始。
ChatBottomBar 的 XML – chat_bottom.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:animateLayoutChanges="true" android:orientation="vertical"> <include layout="@layout/chat_bottom_input"></include> <include layout="@layout/chat_bottom_function1"></include> </LinearLayout>
以下分別是 輸入框的 xml 和 Emoji 的 xml:
chat_bottom_input:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f0f0f0">
<ImageView
android:id="@+id/showMore"
android:layout_width="42dp"
android:layout_height="60dp"
android:paddingBottom="5dp"
android:paddingLeft="9dp"
android:paddingTop="9dp"
android:src="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:layout_toRightOf="@+id/showMore"
android:background="@drawable/shape_white_corner"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="45dp"
android:layout_height="40dp"
android:paddingBottom="10dp"
android:paddingLeft="10dp"
android:paddingRight="5dp"
android:paddingTop="10dp"
android:src="@mipmap/ic_launcher" />
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginRight="10dp"
android:background="@null"
android:gravity="center_vertical"
android:hint="說(shuō)點(diǎn)什么"
android:maxLines="3"
android:textColor="#999999"
android:textColorHint="#dddddd"
android:textSize="13sp" />
</LinearLayout>
</RelativeLayout>
</merge>
chat_bottom_function1:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/emojes"
android:layout_width="match_parent"
android:layout_height="110dp"></android.support.v4.view.ViewPager>
</LinearLayout>
首先是 viewpager 填充 gridView,從 PageAdapter 看起,看看需要哪些數(shù)據(jù):
package cjh.emojicondemo;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.GridView;
import java.util.ArrayList;
/**
* Created by cjh on 16-11-8.
*/
public class EmojiPageAdapter extends PagerAdapter {
private ArrayList<GridView> mLists;
public EmojiPageAdapter(Context context, ArrayList<GridView> array) {
this.mLists = array;
}
@Override
public int getCount() {
return mLists.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(View arg0, int arg1) {
((ViewPager) arg0).addView(mLists.get(arg1));
return mLists.get(arg1);
}
@Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
}
其實(shí)基本就是PagerAdapter的模板代碼,需要的僅僅只是 gridView,看下在ChatbottomBar中的代碼:
@BindView(R.id.emojes)
android.support.v4.view.ViewPager emojes;
....
//每一頁(yè)有24個(gè)表情,然后使用Math的ceil函數(shù),計(jì)算出我們需要的最小頁(yè)數(shù)
private void initEmoje() {
int pageCount = (int) Math.ceil(EmojiUtils.emojis.length / 24.0f);
ArrayList<GridView> pageData = new ArrayList<>();
for (int i = 0; i < pageCount; i++) {
GridView gv = getGridView(i);
pageData.add(gv);
}
emojes.setAdapter(new EmojiPageAdapter(context, pageData));
}
大結(jié)構(gòu)基本就是這樣了,接著就是小細(xì)節(jié)了,比如gridView的創(chuàng)建和展示:
@NonNull
private GridView getGridView(int i) {
GridView gv = new GridView(context);
gv.setVerticalScrollBarEnabled(false);
gv.setAdapter(new EmojiGridAdapter(context, i));
gv.setGravity(Gravity.CENTER);
gv.setClickable(true);
gv.setFocusable(true);
gv.setNumColumns(8);
return gv;
}
adapter:
package cjh.emojicondemo;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import org.greenrobot.eventbus.EventBus;
/**
* Created by cjh on 16-11-8.
*/
public class EmojiGridAdapter extends BaseAdapter {
private Context context;
private int page;
public EmojiGridAdapter(Context context, int page) {
this.context = context;
this.page = page;
}
@Override
public int getCount() {
return 24;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
if (view == null) {
view = LayoutInflater.from(context).inflate(R.layout.chat_emoji, null);
holder = new ViewHolder();
holder.image = (ImageView) view.findViewById(R.id.image);
view.setTag(holder);
}
holder = (ViewHolder) view.getTag();
int position = page * 23 + i;
if (position < EmojiUtils.emojis.length)
ImageLoader.load(context, EmojiUtils.icons[position], holder.image);
else
holder.image.setVisibility(View.GONE);
holder.image.setOnClickListener(view1 -> EventBus.getDefault().post(new EmojiEvent(EmojiUtils.emojis[page * 23 + i])));
return view;
}
static class ViewHolder {
public ImageView image;
}
}
在這里,點(diǎn)擊時(shí)間的傳遞我使用的是EventBus。
大結(jié)構(gòu)基本已經(jīng)OK了,接著就要看比較核心的部分,Emoji 的處理,在接收到Event事件時(shí),調(diào)用了chatBottomBar.appandEmoje(emojiEvent.s)
@Subscribe
public void onEmojiEvent(EmojiEvent emojiEvent) {
chatBottomBar.appandEmoje(emojiEvent.s);
}
那么來(lái)看看ChatBottomBar的代碼:
public void appandEmoje(String s) {
rx.Observable
.just(s)
.subscribeOn(Schedulers.io())
.map(s1 -> {
SpannableString emojeText = EmojiUtils.getEmojiText(editText.getText().toString() + s1);
return emojeText;
})
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s2 -> {
editText.setText("");
editText.append(s2);
});
}
上面代碼使用了RXJAVA,可以看到真正的核心是在
EmojiUtils.getEmojiText(editText.getText().toString() + s1);
return emojeText;這行代碼里面。
那么就來(lái)看看 EmojiUtils 的代碼吧:
package cjh.emojicondemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.text.style.RelativeSizeSpan;
import android.util.SparseArray;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.Inflater;
/**
* Created by cjh on 16-11-7.
*/
public class EmojiUtils {
private static HashMap<Pattern, Integer> emoMap = new HashMap<>();
public static final String DELETE_KEY = "em_delete_delete_expression";
public static String[] emojis = new String[]{
"[微笑]",
"[撇嘴]",
"[色]",
"[發(fā)呆]",
"[得意]",
"[流淚]",
"[害羞]",
"[閉嘴]",
"[睡]",
"[大哭]",
"[尷尬]",
"[發(fā)怒]",
"[調(diào)皮]",
"[呲牙]",
"[驚訝]",
"[難過(guò)]",
"[酷]",
"[冷汗]",
"[抓狂]",
"[吐]",
"[偷笑]",
"[愉快]",
"[白眼]",
"[傲慢]",
"[饑餓]",
"[困]",
"[驚恐]",
"[流汗]",
"[憨笑]",
"[悠閑]",
"[奮斗]",
"[咒罵]",
"[疑問(wèn)]",
"[噓]",
"[暈]",
"[瘋了]",
"[衰]",
"[骷髏]",
"[敲打]",
"[再見(jiàn)]",
"[擦汗]",
"[摳鼻]",
"[鼓掌]",
"[糗大了]",
"[壞笑]",
"[左哼哼]",
"[右哼哼]",
"[哈欠]",
"[鄙視]",
"[委屈]",
"[快哭了]",
"[陰險(xiǎn)]",
"[親親]",
"[嚇]",
"[可憐]",
"[菜刀]",
"[西瓜]",
"[啤酒]",
"[籃球]",
"[乒乓]",
"[咖啡]",
"[飯]",
"[豬頭]",
"[玫瑰]",
"[凋謝]",
"[嘴唇]",
"[愛(ài)心]",
"[心碎]",
"[蛋糕]",
"[閃電]",
"[炸彈]",
"[刀]",
"[足球]",
"[瓢蟲(chóng)]",
"[便便]",
"[月亮]",
"[太陽(yáng)]",
"[禮物]",
"[擁抱]",
"[強(qiáng)]",
"[弱]",
"[握手]",
"[勝利]",
"[抱拳]",
"[勾引]",
"[拳頭]",
"[差勁]",
"[愛(ài)你]",
"[NO]",
"[OK]"
};
public static int[] icons = new int[]{
R.drawable.ee_1,
R.drawable.ee_2,
R.drawable.ee_3,
R.drawable.ee_4,
R.drawable.ee_5,
R.drawable.ee_6,
R.drawable.ee_7,
R.drawable.ee_8,
R.drawable.ee_9,
R.drawable.ee_10,
R.drawable.ee_11,
R.drawable.ee_12,
R.drawable.ee_13,
R.drawable.ee_14,
R.drawable.ee_15,
R.drawable.ee_16,
R.drawable.ee_17,
R.drawable.ee_18,
R.drawable.ee_19,
R.drawable.ee_20,
R.drawable.ee_21,
R.drawable.ee_22,
R.drawable.ee_23,
R.drawable.ee_24,
R.drawable.ee_25,
R.drawable.ee_26,
R.drawable.ee_27,
R.drawable.ee_28,
R.drawable.ee_29,
R.drawable.ee_30,
R.drawable.ee_31,
R.drawable.ee_32,
R.drawable.ee_33,
R.drawable.ee_34,
R.drawable.ee_35,
R.drawable.ee_36,
R.drawable.ee_37,
R.drawable.ee_38,
R.drawable.ee_39,
R.drawable.ee_40,
R.drawable.ee_41,
R.drawable.ee_42,
R.drawable.ee_43,
R.drawable.ee_44,
R.drawable.ee_45,
R.drawable.ee_46,
R.drawable.ee_47,
R.drawable.ee_48,
R.drawable.ee_49,
R.drawable.ee_50,
R.drawable.ee_51,
R.drawable.ee_52,
R.drawable.ee_53,
R.drawable.ee_54,
R.drawable.ee_55,
R.drawable.ee_56,
R.drawable.ee_57,
R.drawable.ee_58,
R.drawable.ee_59,
R.drawable.ee_60,
R.drawable.ee_61,
R.drawable.ee_62,
R.drawable.ee_63,
R.drawable.ee_64,
R.drawable.ee_65,
R.drawable.ee_66,
R.drawable.ee_67,
R.drawable.ee_68,
R.drawable.ee_69,
R.drawable.ee_70,
R.drawable.ee_71,
R.drawable.ee_72,
R.drawable.ee_73,
R.drawable.ee_74,
R.drawable.ee_75,
R.drawable.ee_76,
R.drawable.ee_77,
R.drawable.ee_78,
R.drawable.ee_79,
R.drawable.ee_80,
R.drawable.ee_81,
R.drawable.ee_82,
R.drawable.ee_83,
R.drawable.ee_84,
R.drawable.ee_85,
R.drawable.ee_86,
R.drawable.ee_87,
R.drawable.ee_88,
R.drawable.ee_89,
R.drawable.ee_90,
};
static {
for (int i = 0; i < emojis.length; i++) {
emoMap.put(Pattern.compile(Pattern.quote(emojis[i])), icons[i]);
}
}
public static SpannableString getEmojiText(String s) {
SpannableString spannable = new SpannableString(s);
for (Map.Entry<Pattern, Integer> entry : emoMap.entrySet()) {
Matcher matcher = entry.getKey().matcher(spannable);
while (matcher.find()) {
for (ImageSpan span : spannable.getSpans(matcher.start(),
matcher.end(), ImageSpan.class))
if (spannable.getSpanStart(span) >= matcher.start()
&& spannable.getSpanEnd(span) <= matcher.end())
spannable.removeSpan(span);
else
break;
Drawable drawable = MainActivity.context.getResources().getDrawable(entry.getValue());
drawable.setBounds(0, 0, 60, 60);
ImageSpan imageSpan = new ImageSpan(drawable);
spannable.setSpan(imageSpan,
matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return spannable;
}
}
這里為了方便知道插入表情的位置,我將emoji對(duì)應(yīng)的中文轉(zhuǎn)化成了Pattern對(duì)象,在getEmojiText里面做了遍歷查詢比對(duì),這也就是為什么我會(huì)使用RX來(lái)異步操作。
基本就到這里了,回過(guò)來(lái)看寫(xiě)的內(nèi)容,自己都懶得吐槽,不過(guò),好在只要有具體的demo,能讀代碼,有沒(méi)有講解其實(shí)都還好,也不用怕自己之后看不懂了。
源碼下載:https://github.com/cjhandroid/EmojiInputDemo
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于Android開(kāi)發(fā)支持表情的實(shí)現(xiàn)詳解
- Android開(kāi)發(fā)技巧之像QQ一樣輸入文字和表情圖像
- Android自帶emoji表情的使用方法詳解
- Android編程實(shí)現(xiàn)QQ表情的發(fā)送和接收完整實(shí)例(附源碼)
- 完整的Android表情功能處理方案
- Android編程開(kāi)發(fā)實(shí)現(xiàn)TextView顯示表情圖像和文字的方法
- 詳解Android過(guò)濾emoji表情正則表達(dá)式
- android高仿微信表情輸入與鍵盤(pán)輸入代碼(詳細(xì)實(shí)現(xiàn)分析)
- Android EdText編輯框禁止輸入表情符號(hào)(使用正則表達(dá)式)
- Android實(shí)現(xiàn)表情功能
相關(guān)文章
Android Style.xml的應(yīng)用詳解及代碼實(shí)現(xiàn)
這篇文章主要介紹了Android Style.xml的應(yīng)用詳解及代碼實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2016-10-10
Android實(shí)現(xiàn)View拖拽跟隨手指移動(dòng)效果
這篇文章主要介紹了Android實(shí)現(xiàn)View拖拽跟隨手指移動(dòng)效果,主要使用setTranslationX() 和setTranslationY() 屬性方法實(shí)現(xiàn)的,需要的朋友參考下吧2017-08-08
Android組件化開(kāi)發(fā)路由的設(shè)計(jì)實(shí)踐
本篇文章主要介紹了Android組件化開(kāi)發(fā)路由的設(shè)計(jì)實(shí)踐,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05
android利用websocket協(xié)議與服務(wù)器通信
這篇文章主要為大家詳細(xì)介紹了android利用websocket協(xié)議與服務(wù)器通信,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
Android中解決RecyclerView各種點(diǎn)擊事件的方法
這篇文章主要介紹了Android中解決RecyclerView各種點(diǎn)擊事件的方法,完美解決RecyclerView點(diǎn)擊事件、長(zhǎng)按事件、子項(xiàng)點(diǎn)擊事件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
android獲取照片的快照 思路及實(shí)現(xiàn)方法
android獲取照片的快照 思路及實(shí)現(xiàn)方法,需要的朋友可以參考一下2013-06-06
Android 上下滾動(dòng)TextSwitcher實(shí)例詳解
這篇文章主要介紹了Android 上下滾動(dòng)TextSwitcher實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06
Android編程實(shí)現(xiàn)小說(shuō)閱讀器滑動(dòng)效果的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)小說(shuō)閱讀器滑動(dòng)效果的方法,涉及onTouch事件滑動(dòng)效果的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android recyclerview實(shí)現(xiàn)縱向虛線時(shí)間軸的示例代碼
本文主要介紹了Android recyclerview實(shí)現(xiàn)縱向虛線時(shí)間軸的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07

