闲来无事花了一点空暇时间写了一个模仿Android版手机QQ的表情输入框
效果图如下
- 一:布局
- 二:录入填充表情
- 三:监听表情的适配器的触摸监听显示出预览框
实现步骤
一 、布局
我是自己自定一个ExpressionGridView(RelativeLayout)只是集成了这些方法的一个自定义View而已
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:id="@+id/expression_text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="223dp"
android:layout_alignParentBottom="true">
<view.ExpressionGridView
android:id="@+id/expression_gridview"
android:layout_width="fill_parent"
android:layout_height="123dp"
android:layout_alignParentBottom="true" />
<RelativeLayout
android:id="@+id/face_view"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="#78072026"
android:visibility="gone">
<!-- 预览框-->
<ImageView
android:id="@+id/face_img"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
二、录入填充表情
下载QQ解压出里面的资源文件获取表情包统一命名规范后定义 因为这些是我以前做个类似软件的时候使用了的现成资源拿来用
定义好的表情
package view;
import anroid.qq_expression.shallcheek.shallcheek_qq_expression.R;
/**
* 表情文件
*
* @author shallcheek
* @version 1.0
*/
public class Expressions {
public static Integer[] expressionImgs = new Integer[]{R.drawable.f001,
R.drawable.f002, R.drawable.f003, R.drawable.f004, R.drawable.f005,
R.drawable.f006, R.drawable.f007, R.drawable.f008, R.drawable.f009,
R.drawable.f010, R.drawable.f011, R.drawable.f012, R.drawable.f013,
R.drawable.f014, R.drawable.f015, R.drawable.f016, R.drawable.f017,
R.drawable.f018, R.drawable.f019, R.drawable.f020, R.drawable.f021,
R.drawable.f022, R.drawable.f023};
/**
* 本地表情的名
*/
public static String[] expressionImgNames = new String[]{"[f001]",
"[f002]", "[f003]", "[f004]", "[f005]", "[f006]", "[f007]",
"[f008]", "[f009]", "[f010]", "[f011]", "[f012]", "[f013]",
"[f014]", "[f015]", "[f016]", "[f017]", "[f018]", "[f019]",
"[f020]", "[f021]", "[f022]", "[f023]"};
public static Integer[] expressionImgs1 = new Integer[]{R.drawable.f024,
R.drawable.f025, R.drawable.f026, R.drawable.f027, R.drawable.f028,
R.drawable.f029, R.drawable.f030, R.drawable.f031, R.drawable.f032,
R.drawable.f033, R.drawable.f034, R.drawable.f035, R.drawable.f036,
R.drawable.f037, R.drawable.f038, R.drawable.f039, R.drawable.f040,
R.drawable.f041, R.drawable.f042, R.drawable.f043, R.drawable.f044,
R.drawable.f045, R.drawable.f046};
/**
* 本地表情的名
*/
public static String[] expressionImgNames1 = new String[]{"[f024]",
"[f025]", "[f026]", "[f027]", "[f028]", "[f029]", "[f030]",
"[f031]", "[f032]", "[f033]", "[f034]", "[f035]", "[f036]",
"[f037]", "[f038]", "[f039]", "[f040]", "[f041]", "[f042]",
"[f043]", "[f044]", "[f045]", "[f046]"};
public static Integer[] expressionImgs2 = new Integer[]{R.drawable.f047,
R.drawable.f048, R.drawable.f049, R.drawable.f050, R.drawable.f051,
R.drawable.f052, R.drawable.f053, R.drawable.f054, R.drawable.f055,
R.drawable.f056, R.drawable.f057, R.drawable.f058, R.drawable.f059,
R.drawable.f060, R.drawable.f061, R.drawable.f062, R.drawable.f063,
R.drawable.f064, R.drawable.f065, R.drawable.f066, R.drawable.f067,
R.drawable.f068, R.drawable.f069};
/**
* 本地表情的名
*/
public static String[] expressionImgNames2 = new String[]{"[f047]",
"[f048]", "[f049]", "[f050]", "[f051]", "[f052]", "[f053]",
"[f054]", "[f055]", "[f056]", "[f057]", "[f058]", "[f059]",
"[f060]", "[f061]", "[f062]", "[f063]", "[f064]", "[f065]",
"[f066]", "[f067]", "[f068]", "[f069]"};
public static Integer[] expressionImgs3 = new Integer[]{R.drawable.f070,
R.drawable.f071, R.drawable.f072, R.drawable.f073, R.drawable.f074,
R.drawable.f075, R.drawable.f076, R.drawable.f077, R.drawable.f078,
R.drawable.f079, R.drawable.f080, R.drawable.f081, R.drawable.f082,
R.drawable.f083, R.drawable.f084, R.drawable.f085, R.drawable.f086,
R.drawable.f087, R.drawable.f088, R.drawable.f089, R.drawable.f090,
R.drawable.f091, R.drawable.f092};
/**
* 本地表情的名
*/
public static String[] expressionImgNames3 = new String[]{"[f070]",
"[f071]", "[f072]", "[f073]", "[f074]", "[f075]", "[f076]",
"[f077]", "[f078]", "[f079]", "[f080]", "[f081]", "[f082]",
"[f083]", "[f084]", "[f085]", "[f086]", "[f087]", "[f088]",
"[f089]", "[f090]", "[f091]", "[f092]"};
public static Integer[] expressionImgs4 = new Integer[]{R.drawable.f093,
R.drawable.f094, R.drawable.f095, R.drawable.f096, R.drawable.f097,
R.drawable.f098, R.drawable.f099, R.drawable.f100, R.drawable.f101,
R.drawable.f102, R.drawable.f103, R.drawable.f104, R.drawable.f105,
R.drawable.f106, R.drawable.f107, R.drawable.f108, R.drawable.f109,
R.drawable.f110, R.drawable.f111, R.drawable.f112, R.drawable.f113,
R.drawable.f114, R.drawable.f115};
/**
* 本地表情的名
*/
public static String[] expressionImgNames4 = new String[]{"[f093]",
"[f094]", "[f095]", "[f096]", "[f097]", "[f098]", "[f099]",
"[f100]", "[f101]", "[f102]", "[f103]", "[f104]", "[f105]",
"[f106]", "[f107]", "[f108]", "[f109]", "[f110]", "[f111]",
"[f112]", "[f113]", "[f114]", "[f115]"};
/**
* 在存入数据库时,将表情名字进行替换即
*/
public static String[] replaceStrings(String[] str, String[] str2) {
String newStr[] = new String[str.length - 1];
for (Integer i = 0; i < str.length; i++) {
newStr[i] = str[i].replace(str[i], str2[i]);
}
return newStr;
}
}
定义好一个mode 将弄成数组制作填充进去
List<ExpressionMode> expressionUtils = new ArrayList<>();
List<Integer> imgs = new ArrayList<>();
imgs.addAll(Arrays.<Integer>asList(Expressions.expressionImgs));
imgs.addAll(Arrays.<Integer>asList(Expressions.expressionImgs1));
imgs.addAll(Arrays.<Integer>asList(Expressions.expressionImgs2));
imgs.addAll(Arrays.<Integer>asList(Expressions.expressionImgs3));
imgs.addAll(Arrays.<Integer>asList(Expressions.expressionImgs4));
List<String> nams = new ArrayList<>();
nams.addAll(Arrays.asList(Expressions.expressionImgNames));
nams.addAll(Arrays.asList(Expressions.expressionImgNames1));
nams.addAll(Arrays.asList(Expressions.expressionImgNames2));
nams.addAll(Arrays.asList(Expressions.expressionImgNames3));
nams.addAll(Arrays.asList(Expressions.expressionImgNames4));
for (int i = 0; i < imgs.size(); i++) {
ExpressionMode expressionMode = new ExpressionMode();
expressionMode.setValue(nams.get(i));
expressionMode.setResources(imgs.get(i));
expressionUtils.add(expressionMode);
}
ExpressionMode.java
/**
* Created by Shall on 2015.9.11.
*/
public class ExpressionMode {
private int resources;
private int resourcesgif;
private String value;
public int getResources() {
return resources;
}
public void setResources(int resources) {
this.resources = resources;
}
public int getResourcesgif() {
return resourcesgif;
}
public void setResourcesgif(int resourcesgif) {
this.resourcesgif = resourcesgif;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
自定义View ExpressionGridView 里面集成了ViewPage 使用GridView填充表情
public void setExpressionModes(List<ExpressionMode> expressionModes) {
this.expressionModes = expressionModes;
page = expressionModes.size() / (PAGE_MAX_NUMBER) + 1;
expressionGridViewList = new ArrayList<>();
for (int i = 0; i < page; i++) {
final GridView gridView = (GridView) View.inflate(getContext(), R.layout.gridview, null);
List<ExpressionMode> list = this.expressionModes.subList(PAGE_MAX_NUMBER * i, PAGE_MAX_NUMBER * (i + 1) > expressionModes.size() ? expressionModes.size() - 1 : PAGE_MAX_NUMBER * (i + 1));
lists.add(list);
if (i == 0) {
this.list = list;
}
final ExpressionAdapter expressionAdatper = new ExpressionAdapter(list, getContext());
gridView.setAdapter(expressionAdatper);
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
expressionViewPager.setScanScroll(true);//屏蔽ViewPage滑动事件
isMove = true;
setSelect(choose);
return false;
}
});
gridView.setOnTouchListener(this);
gridView.setOnItemClickListener(this);
expressionGridViewList.add(gridView);
}
expressionViewPager = (ExpressionViewPager) View.inflate(getContext(), R.layout.viewpage, null);
addView(expressionViewPager);
PagerAdapter mPagerAdapter = new PagerAdapter() {
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public int getCount() {
return expressionGridViewList.size();
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView(expressionGridViewList.get(position));
}
@Override
public Object instantiateItem(View container, int position) {
((ViewPager) container).addView(expressionGridViewList.get(position));
return expressionGridViewList.get(position);
}
};
expressionViewPager.setAdapter(mPagerAdapter);
expressionViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// relativeLayout.setVisibility(GONE);
// imageView.setVisibility(View.GONE);
}
@Override
public void onPageSelected(int position) {
list = lists.get(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
表情的插入根据OnItemClickListener 的点击获取到点击的mode 填充到输入框
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ExpressionAdapter expressionAdapter = (ExpressionAdapter) parent.getAdapter();
ExpressionMode expressionMode = (ExpressionMode) expressionAdapter.getItem(position);
ExpressionUtil.installExpression(getContext(), editText, expressionMode);
}
实现代码
/**
* 插入表情
*/
public static void installExpression(Context mCon, EditText mEditTextContent, ExpressionMode expressionMode) {
Bitmap bitmap = BitmapFactory.decodeResource(mCon.getResources(), expressionMode.getResources());
bitmap = Bitmap.createScaledBitmap(bitmap, dip2px(30, mCon), dip2px(30, mCon), true);
ImageSpan imageSpan = new ImageSpan(mCon, bitmap);
SpannableString spannableString = new SpannableString(expressionMode.getValue().substring(1, expressionMode.getValue().length() - 1));
spannableString.setSpan(imageSpan, 0, expressionMode.getValue().length() - 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mEditTextContent.getText().insert(mEditTextContent.getSelectionStart(), spannableString);
}
三、滑动监听探出预览框
获取到到View的滑动X,Y左边计算出滑动的item 并展示出来预览框
//首先需要长按时间完成之后才处理监听事件 屏蔽ViewPage的事件监听
gridView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
expressionViewPager.setScanScroll(true);//屏蔽ViewPage滑动事件
isMove = true;
setSelect(choose);
return false;
}
});
gridView.setOnTouchListener(this);
触摸事件的处理
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
Log.e("12","x:"+x+"y:"+y);
int heighnum = (int) (y / (v.getHeight() / VERTICAL_NUMBER));
int widthnum = (int) (x / (v.getWidth() / TRANSVERSE_NUMBER));
//超出View 范围
if (heighnum <= 0) heighnum = 0;
if (heighnum >= VERTICAL_NUMBER) heighnum = VERTICAL_NUMBER - 1;
if (widthnum <= 0) widthnum = 0;
if (widthnum >= TRANSVERSE_NUMBER) widthnum = TRANSVERSE_NUMBER - 1;
//没有填充满
int listSize = list.size();
if (heighnum >= listSize / TRANSVERSE_NUMBER && widthnum >= listSize % TRANSVERSE_NUMBER) {
widthnum = listSize % TRANSVERSE_NUMBER;
heighnum = listSize / TRANSVERSE_NUMBER;
heighnum--;
}
final int c = (heighnum) * TRANSVERSE_NUMBER + widthnum;
choose = c;
if (choose >= listSize)
choose = listSize - 1;//需要减1 不要越界
switch (action) {
case MotionEvent.ACTION_UP:
choose = -1;//
expressionViewPager.setScanScroll(false);
isMove = false;
relativeLayout.setVisibility(GONE);
imageView.setVisibility(View.GONE);
break;
default:
if (isMove)
setSelect(choose);
break;
}
return false;
}
ViewPage监听处理
public class ExpressionViewPager extends ViewPager {
private boolean isCanScroll = false;
public ExpressionViewPager(Context context) {
super(context);
}
public ExpressionViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScanScroll(boolean isCanScroll) {
this.isCanScroll = isCanScroll;
}
@Override
protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
if (v instanceof ViewPager) {
return isCanScroll;
}
return super.canScroll(v, checkV, dx, x, y);
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
}
imageView.setVisibility(View.VISIBLE);
relativeLayout.setVisibility(VISIBLE);
int w = choose % TRANSVERSE_NUMBER;
int h = choose / TRANSVERSE_NUMBER;
//设置弹出框的大小个位置
View v = expressionGridViewList.get(0);
RelativeLayout.LayoutParams layoutParams = new LayoutParams((v.getWidth() / TRANSVERSE_NUMBER), (v.getWidth() / TRANSVERSE_NUMBER));
layoutParams.setMargins(w * (v.getWidth() / TRANSVERSE_NUMBER), (h) * (v.getHeight() / VERTICAL_NUMBER) - 30 + v.getHeight() / VERTICAL_NUMBER, 0, 0);
relativeLayout.setLayoutParams(layoutParams);
imageView.setBackgroundResource(list.get(choose > list.size() ? list.size() : select).getResources());
介绍的简单凑合着看吧 不懂可以留言可以加我微信 shallcheek