实现效果如下图所示。
代码下载链接:http://download.csdn.net/detail/laukaka/5657891
代码如下:
MainActivity.java
package com.example.textfacedemo;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import com.example.textfacedemo.FaceLayout.OnFaceClickListener;
public class MainActivity extends Activity implements OnClickListener {
private View btnFace;
private View btnSend;
private FaceLayout faceLayout;
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initView() {
btnFace = findViewById(R.id.msg_comm_btn_menu);
btnSend = findViewById(R.id.msg_comm_btn_send_msg);
editText = (EditText) findViewById(R.id.msg_comm_msg_edit);
faceLayout = (FaceLayout) findViewById(R.id.msg_comm_face_layout);
}
private void initListener() {
btnFace.setOnClickListener(this);
btnSend.setOnClickListener(this);
editText.setOnClickListener(this);
faceLayout.setOnFaceClickListener(faceClickListener);
}
@Override
public void onClick(View v) {
if(v.getId() == btnFace.getId()) {
((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(btnFace.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
if(faceLayout.getVisibility() == View.GONE) {
faceLayout.setVisibility(View.VISIBLE);
} else {
faceLayout.setVisibility(View.GONE);
}
} else if(v.getId() == btnSend.getId()) {
} else if(v.getId() == editText.getId()) {
faceLayout.setVisibility(View.GONE);
}
}
private OnFaceClickListener faceClickListener = new OnFaceClickListener() {
@Override
public void faceClick(String face) {
if(face != null && !face.equals("")) {
int selection = editText.getSelectionEnd();
String newStr = editText.getText().toString();
int origLength = newStr.length();
if(face.equals("delete")) {
KeyEvent keyEventDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
editText.onKeyDown(KeyEvent.KEYCODE_DEL, keyEventDown);
newStr = editText.getText().toString();
} else {
newStr = newStr.substring(0, editText.getSelectionEnd()) + face + newStr.substring(editText.getSelectionEnd(), newStr.length());
}
SpannableStringBuilder spannableString = getContentList(newStr);
if(spannableString != null) {
int newLength = newStr.length();
selection += (newLength - origLength);
editText.setText(spannableString);
Log.d("DEBUG", "orig length: " + origLength + "; new length: " + newLength + "; selection:" + selection);
editText.setSelection(selection);
}
}
}
};;
public static final String FACE_STRING =
"[可怜],[微笑],[撇嘴],[色],[发呆],[得意],[流泪],[害羞],[闭嘴],[睡]," +
"[大哭],[尴尬],[发怒],[调皮],[呲牙],[惊讶],[难过],[酷],[冷汗],[抓狂]," +
"[吐],[偷笑],[愉快],[白眼],[傲慢],[饥饿],[困],[惊恐],[流汗],[憨笑]," +
"[悠闲],[奋斗],[咒骂],[疑问],[嘘],[晕],[疯了],[衰],[骷髅],[敲打]," +
"[再见],[擦汗],[抠鼻],[鼓掌],[糗大了],[坏笑],[左哼哼],[右哼哼],[哈欠],[鄙视]," +
"[委屈],[快哭了],[阴险],[亲亲],[吓]";
private static final HashMap<String, SoftReference<Bitmap>> mFaceBitmapCache = new HashMap<String, SoftReference<Bitmap>>();
private static final String FACE_PATTERN = "\\[.*?\\]";
public static HashMap<Integer, String> FACE_STR = new HashMap<Integer, String>(); //表情的位置对应的字符串
public static HashMap<String, Integer> FACE_STR_MAP_ID = new HashMap<String, Integer>(); //表情的字符串对应的资源ID
public static HashMap<Integer, Integer> FACE_IMG_RES_ID = new HashMap<Integer, Integer>(); //表情的位置对应的资源ID
static {
String[] faceStr = FACE_STRING.split(",");
for(int i=0; i<faceStr.length; i++) {
FACE_IMG_RES_ID.put(i, R.drawable.face_00 + i);
FACE_STR_MAP_ID.put(faceStr[i], R.drawable.face_00 + i);
FACE_STR.put(i, faceStr[i]);
}
}
// 在使用SpannableString对象时要注意Spanned.SPAN_EXCLUSIVE_EXCLUSIVE等的作用:
// 用来标识在 Span 范围内的文本前后输入新的字符时是否把它们也应用这个效果。
// 分别有 Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、
// Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)、
// Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、
// Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)。
public SpannableStringBuilder getContentList(String line) {
if(line == null || line.equals("")) {
return null;
}
SpannableStringBuilder ssb = new SpannableStringBuilder(line);
Pattern pattern = Pattern.compile("(" + FACE_PATTERN + ")");
Matcher matcher = pattern.matcher(line);
while(matcher.find()) {
int start = matcher.start();
int end = matcher.end();
String words = line.substring(start, end);
if(words.matches("^" + FACE_PATTERN + "$") && FACE_STRING.contains(words)) {
try{
Bitmap bitmap = null;
SoftReference<Bitmap> bitmapReference = mFaceBitmapCache.get(words);
if(bitmapReference != null) {
bitmap = bitmapReference.get();
if(bitmap == null) {
bitmap = getBitMap(FACE_STR_MAP_ID.get(words));
mFaceBitmapCache.put(words, new SoftReference<Bitmap>(bitmap));
}
} else {
bitmap = getBitMap(FACE_STR_MAP_ID.get(words));
mFaceBitmapCache.put(words, new SoftReference<Bitmap>(bitmap));
}
if(bitmap != null) {
ImageSpan imageSpan = new ImageSpan(bitmap);
ssb.setSpan(imageSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (Exception e){
e.printStackTrace();
}
}
matcher.region(end, line.length());
}
return ssb;
}
private Bitmap getBitMap(int id) {
try {
Bitmap bm = BitmapFactory.decodeResource(getResources(), id);
return bm;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
FaceLayout.java
package com.example.textfacedemo;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class FaceLayout extends LinearLayout {
private ViewPager layoutFaceQQ;
private LinearLayout faceLayoutIndexLayout;
private OnFaceClickListener faceClickListener;
private int currentPageIndex = 0;
public FaceLayout(Context context) {
super(context);
init();
}
public FaceLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.face_layout, this);
layoutFaceQQ = (ViewPager) findViewById(R.id.msg_face_layout_qq);
faceLayoutIndexLayout = (LinearLayout) findViewById(R.id.msg_face_layout_index);
layoutFaceQQ.setAdapter(new ViewPageAdapter(MainActivity.FACE_IMG_RES_ID, 24));
layoutFaceQQ.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int arg0) {
initPageIndex(layoutFaceQQ.getAdapter().getCount(), arg0);
}
@Override
public void onPageScrollStateChanged(int arg0) { }
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) { }
});
}
private void initPageIndex(int pageNum, int index) {
currentPageIndex = index;
if(pageNum > 1) {
faceLayoutIndexLayout.removeAllViews();
for(int i=0; i<pageNum; i++) {
ImageView iv = new ImageView(getContext());
if(i == index) {
iv.setBackgroundResource(R.drawable.dot_abled);
} else {
iv.setBackgroundResource(R.drawable.dot_unabled);
}
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.setMargins(8, 5, 8, 5);
faceLayoutIndexLayout.addView(iv, lp);
}
}
}
private View getFaceViews(HashMap<Integer, Integer> faceMap, final int index, final int num) {
GridView gv = new GridView(getContext());
gv.setNumColumns(8);
gv.setAdapter(new FaceGridViewAdapter(faceMap, index, num));
gv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
String face = null;
if(arg2 == (num - 1)) {
face = "delete";
} else {
face = MainActivity.FACE_STR.get((currentPageIndex * (num - 1)) + arg2);
}
if(face != null && faceClickListener != null) {
faceClickListener.faceClick(face);
}
}
});
gv.setSelector(R.drawable.face_sel_bg);
return gv;
}
public void setOnFaceClickListener(OnFaceClickListener listener) {
faceClickListener = listener;
}
class ViewPageAdapter extends PagerAdapter {
private List<View> views;
private HashMap<Integer, Integer> facesResIdMap; //表情的资源ID列表
private int pageNum; //表情的页数
private int iconNumOfPage; //一个页面具有的表情数
public ViewPageAdapter(HashMap<Integer, Integer> facesMap, int iconNumOfPage) {
this.facesResIdMap = facesMap;
this.iconNumOfPage = iconNumOfPage;
this.views = new ArrayList<View>();
if(facesMap == null) {
this.pageNum = 0;
} else {
this.pageNum = facesMap.size() % iconNumOfPage > 0 ? facesMap.size() / iconNumOfPage + 1 : facesMap.size() / iconNumOfPage;
initPageIndex(pageNum, 0);
}
}
@Override
public int getCount() {
return pageNum;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = getFaceViews(facesResIdMap, position, iconNumOfPage);
views.add(view);
container.addView(view);
return view;
}
}
class FaceGridViewAdapter extends BaseAdapter {
private HashMap<Integer, Integer> facesResIdMap;
private int pageIconNum;
private int pageIndex = 0;
public FaceGridViewAdapter(HashMap<Integer, Integer> faceMap, int index, int num) {
this.facesResIdMap = faceMap;
this.pageIconNum = num;
this.pageIndex = index;
}
@Override
public int getCount() {
return pageIconNum;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = new ImageView(getContext());
}
if(position == (pageIconNum - 1)) {
((ImageView) convertView).setImageResource(R.drawable.face_delete);
} else {
Integer imgId = facesResIdMap.get((pageIndex * (pageIconNum - 1)) + position);
if(imgId != null) {
((ImageView) convertView).setImageResource(imgId);
} else {
((ImageView) convertView).setImageResource(R.drawable.face_delete);
convertView.setVisibility(View.INVISIBLE);
}
}
convertView.setPadding(2, 6, 2, 6);
return convertView;
}
}
public interface OnFaceClickListener {
public void faceClick(String face);
}
}