经过一个星期的折腾,最终做完了这个Android 聊天表情输入、表情翻页带效果、下拉刷新聊天记录。这仅仅是一个单独聊天表情的输入,以及聊天的效果实现。由于我没有写server,所以没有两方聊天的效果。

主要是聊天中表情的选择。发送。

表情翻页带有不同的效果。

我在主要代码中都写了凝视。以下看代码实现。附上本文源代码,代码较多。

下载地址:点击

一、先看实现的效果图

二、调用接口以及设置MainActivity

package com.example.activity;

import java.util.ArrayList;
import java.util.List;
import java.util.Set; import com.org.adapter.FaceAdapter;
import com.org.adapter.FacePageAdeapter;
import com.org.adapter.MessageAdapter;
import com.org.util.MyApplication;
import com.org.util.SharePreferenceUtil;
import com.org.view.CirclePageIndicator;
import com.org.view.JazzyViewPager;
import com.org.view.JazzyViewPager.TransitionEffect;
import com.org.xlistview.MsgListView;
import com.org.xlistview.MsgListView.IXListViewListener;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.drawable.ColorDrawable;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextWatcher;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener; public class MainActivity extends Activity
implements
OnClickListener,
OnTouchListener,
IXListViewListener{ private Button sendBtn;
private ImageButton faceBtn;
private LinearLayout faceLinearLayout;
private EditText msgEt;
private InputMethodManager mInputMethodManager;
private MessageAdapter mMessageAdapter;
private JazzyViewPager faceViewPager;
private MsgListView mMsgListView;
private MyApplication mApplication;
private SharePreferenceUtil mSpUtil;
private WindowManager.LayoutParams mLayoutParams;
private List<String> mListFaceKeys;
private int currentPage = 0;
private boolean isFaceShow = false;
private static int MsgPagerNum;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_main);
initData();
initUI();
initFacePage();
} private void initData() {
mApplication = MyApplication.getInstance();
//SharePreference存储类
mSpUtil = new SharePreferenceUtil(this, "message_save");
//初始化消息列表适配器
mMessageAdapter = new MessageAdapter(this, initMsgData()); //载入表情的列表
Set<String> keySet = MyApplication.getInstance().getFaceMap().keySet();
mListFaceKeys = new ArrayList<String>();
mListFaceKeys.addAll(keySet);
MsgPagerNum = 0;
}
private void initUI() {
mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
//获取窗体触摸操作
mLayoutParams = getWindow().getAttributes(); mMsgListView = (MsgListView) findViewById(R.id.msg_listView);
// 触摸ListView隐藏表情和输入法
mMsgListView.setOnTouchListener(this);
mMsgListView.setPullLoadEnable(false);
mMsgListView.setXListViewListener(this);
mMsgListView.setAdapter(mMessageAdapter);
mMsgListView.setSelection(mMessageAdapter.getCount() - 1); sendBtn = (Button) findViewById(R.id.send_btn);
faceBtn = (ImageButton) findViewById(R.id.face_btn);
faceLinearLayout = (LinearLayout) findViewById(R.id.face_ll);
msgEt = (EditText) findViewById(R.id.msg_et);
faceLinearLayout = (LinearLayout) findViewById(R.id.face_ll);
faceViewPager = (JazzyViewPager) findViewById(R.id.face_pager); //标题栏控件
TextView mTitle = (TextView) findViewById(R.id.ivTitleName);
mTitle.setText("默默笙箫");
TextView mTitleLeftBtn = (TextView) findViewById(R.id.ivTitleBtnLeft);
mTitleLeftBtn.setVisibility(View.VISIBLE);
mTitleLeftBtn.setOnClickListener(this); //输入框的触摸监听的绑定
msgEt.setOnTouchListener(this);
msgEt.setOnKeyListener(new OnKeyListener() { @Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (mLayoutParams.softInputMode == WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
|| isFaceShow) {
faceLinearLayout.setVisibility(View.GONE);
isFaceShow = false;
// imm.showSoftInput(msgEt, 0);
return true;
}
}
return false;
}
}); //输入框的实时输入长度的监听
msgEt.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
} @Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
} @Override
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
sendBtn.setEnabled(true);
} else {
sendBtn.setEnabled(false);
}
}
}); faceBtn.setOnClickListener(this);
sendBtn.setOnClickListener(this);
} @Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.msg_listView: //ListView触摸实现
mInputMethodManager.hideSoftInputFromWindow(msgEt.getWindowToken(), 0);
faceLinearLayout.setVisibility(View.GONE);
isFaceShow = false;
break;
case R.id.msg_et: //输入框触摸实现
mInputMethodManager.showSoftInput(msgEt, 0);
faceLinearLayout.setVisibility(View.GONE);
isFaceShow = false;
break; default:
break;
}
return false;
} //历史数据。在開始时显示
private List<MessageItem> initMsgData() {
List<MessageItem> msgList = new ArrayList<MessageItem>();// 消息对象数组 MessageItem item = new MessageItem(MessageItem.MESSAGE_TYPE_TEXT,
mSpUtil.getNick(), System.currentTimeMillis(), "历史消息",
mSpUtil.getHeadIcon(), false, 0);
msgList.add(item);
return msgList; } @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.face_btn: //弹出表情
if (!isFaceShow) {
mInputMethodManager.hideSoftInputFromWindow(msgEt.getWindowToken(), 0);
try {
Thread.sleep(80);// 解决此时会黑一下屏幕的问题
} catch (InterruptedException e) {
e.printStackTrace();
}
faceLinearLayout.setVisibility(View.VISIBLE);
isFaceShow = true;
} else {
faceLinearLayout.setVisibility(View.GONE);
isFaceShow = false;
}
break;
case R.id.send_btn:// 发送消息
String msg = msgEt.getText().toString();
MessageItem item = new MessageItem(MessageItem.MESSAGE_TYPE_TEXT,
mSpUtil.getNick(), System.currentTimeMillis(), msg,
mSpUtil.getHeadIcon(), false, 0);
mMessageAdapter.upDateMsg(item); mMsgListView.setSelection(mMessageAdapter.getCount() - 1);
msgEt.setText("");
break;
case R.id.ivTitleBtnLeft:
finish();
break;
// case R.id.ivTitleBtnRigh:
// break;
default:
break;
} } //载入表情。以及设置翻页效果
private void initFacePage() {
List<View> lv = new ArrayList<View>();
for (int i = 0; i < MyApplication.NUM_PAGE; ++i)
lv.add(getGridView(i));
FacePageAdeapter adapter = new FacePageAdeapter(lv, faceViewPager);
faceViewPager.setAdapter(adapter);
faceViewPager.setCurrentItem(currentPage);
faceViewPager.setTransitionEffect(mEffects[mSpUtil.getFaceEffect()]);
CirclePageIndicator indicator = (CirclePageIndicator) findViewById(R.id.indicator);
indicator.setViewPager(faceViewPager);
adapter.notifyDataSetChanged();
faceLinearLayout.setVisibility(View.GONE);
indicator.setOnPageChangeListener(new OnPageChangeListener() { @Override
public void onPageSelected(int arg0) {
currentPage = arg0;
} @Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// do nothing
} @Override
public void onPageScrollStateChanged(int arg0) {
// do nothing
}
}); } //表情表格控件放置。设置背景
private GridView getGridView(int i) {
GridView gv = new GridView(this);
gv.setNumColumns(7); //一行显示7个表情
gv.setSelector(new ColorDrawable(Color.TRANSPARENT));// 屏蔽GridView默认点击效果
gv.setBackgroundColor(Color.TRANSPARENT);
gv.setCacheColorHint(Color.TRANSPARENT);
gv.setHorizontalSpacing(1);
gv.setVerticalSpacing(1);
gv.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
gv.setGravity(Gravity.CENTER);
gv.setAdapter(new FaceAdapter(this, i));
gv.setOnTouchListener(forbidenScroll()); // 防止乱pageview乱滚动
gv.setOnItemClickListener(new OnItemClickListener() { @Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
if (arg2 == MyApplication.NUM) { // 删除表情键的位置
int selection = msgEt.getSelectionStart();
String text = msgEt.getText().toString();
if (selection > 0) {
String text2 = text.substring(selection - 1);
if ("]".equals(text2)) {
int start = text.lastIndexOf("[");
int end = selection;
msgEt.getText().delete(start, end);
return;
}
msgEt.getText().delete(selection - 1, selection);
}
} else {
int count = currentPage * MyApplication.NUM + arg2;
// 凝视的部分,在EditText中显示字符串
// String ori = msgEt.getText().toString();
// int index = msgEt.getSelectionStart();
// StringBuilder stringBuilder = new StringBuilder(ori);
// stringBuilder.insert(index, keys.get(count));
// msgEt.setText(stringBuilder.toString());
// msgEt.setSelection(index + keys.get(count).length()); // 以下这部分。在EditText中显示表情
Bitmap bitmap = BitmapFactory.decodeResource(
getResources(), (Integer) MyApplication
.getInstance().getFaceMap().values()
.toArray()[count]);
if (bitmap != null) {
int rawHeigh = bitmap.getHeight();
int rawWidth = bitmap.getHeight();
int newHeight = 40;
int newWidth = 40;
// 计算缩放因子
float heightScale = ((float) newHeight) / rawHeigh;
float widthScale = ((float) newWidth) / rawWidth;
// 新建立矩阵
Matrix matrix = new Matrix();
matrix.postScale(heightScale, widthScale);
// 设置图片的旋转角度
// matrix.postRotate(-30);
// 设置图片的倾斜
// matrix.postSkew(0.1f, 0.1f);
// 将图片大小压缩
// 压缩后图片的宽和高以及kB大小均会变化
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0,
rawWidth, rawHeigh, matrix, true);
ImageSpan imageSpan = new ImageSpan(MainActivity.this,
newBitmap);
String emojiStr = mListFaceKeys.get(count);
SpannableString spannableString = new SpannableString(
emojiStr);
spannableString.setSpan(imageSpan,
emojiStr.indexOf('['),
emojiStr.indexOf(']') + 1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
msgEt.append(spannableString);
} else {
String ori = msgEt.getText().toString();
int index = msgEt.getSelectionStart();
StringBuilder stringBuilder = new StringBuilder(ori);
stringBuilder.insert(index, mListFaceKeys.get(count));
msgEt.setText(stringBuilder.toString());
msgEt.setSelection(index + mListFaceKeys.get(count).length());
}
}
}
});
return gv;
} // 防止乱pageview乱滚动
private OnTouchListener forbidenScroll() {
return new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
return true;
}
return false;
}
};
} @Override
protected void onPause() {
// TODO Auto-generated method stub
mInputMethodManager.hideSoftInputFromWindow(msgEt.getWindowToken(), 0);
faceLinearLayout.setVisibility(View.GONE);
isFaceShow = false;
super.onPause();
} //处理下拉刷新的效果
@Override
public void onRefresh() {
MsgPagerNum++;
List<MessageItem> msgList = initMsgData();
int position = mMessageAdapter.getCount();
mMessageAdapter.setMessageList(msgList);
mMsgListView.stopRefresh(); mMsgListView.setSelection(mMessageAdapter.getCount() - position - 1);
Log.i("Show","MsgPagerNum = " + mMessageAdapter + ", adapter.getCount() = "
+ mMessageAdapter.getCount()); }
@Override
public void onLoadMore() {
// TODO Auto-generated method stub } private TransitionEffect mEffects[] = { TransitionEffect.Standard,
TransitionEffect.Tablet, TransitionEffect.CubeIn,
TransitionEffect.CubeOut, TransitionEffect.FlipVertical,
TransitionEffect.FlipHorizontal, TransitionEffect.Stack,
TransitionEffect.ZoomIn, TransitionEffect.ZoomOut,
TransitionEffect.RotateUp, TransitionEffect.RotateDown,
TransitionEffect.Accordion, };// 表情翻页效果 }

二、基本的xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" > <include layout="@layout/common_title_bg" /> <FrameLayout
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="1.0"
android:background="@drawable/chat_bg_01" > <com.org.xlistview.MsgListView
android:id="@+id/msg_listView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="@null"
android:listSelector="@android:color/transparent"
android:transcriptMode="normal" />
</FrameLayout> <LinearLayout
android:id="@+id/inputBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottombar_bg"
android:gravity="center_vertical" > <!-- <ImageButton
android:id="@+id/more_btn"
android:layout_width="42.0dip"
android:layout_height="fill_parent"
android:background="@android:color/transparent"
android:paddingLeft="10.0dip"
android:src="@drawable/pop_btn_selector" /> --> <ImageButton
android:id="@+id/face_btn"
android:layout_width="42.0dip"
android:layout_height="fill_parent"
android:background="@android:color/transparent"
android:paddingLeft="5.0dip"
android:paddingRight="5.0dip"
android:src="@drawable/pop_btn_face_selector" /> <EditText
android:id="@+id/msg_et"
android:layout_width="0.0dip"
android:layout_height="40dip"
android:layout_marginBottom="6.0dip"
android:layout_marginTop="6.0dip"
android:layout_weight="1.0"
android:background="@drawable/chat_bottombar_input"
android:inputType="textMultiLine"
android:maxHeight="68.0dip"
android:paddingBottom="4.0dip"
android:paddingLeft="10.0dip"
android:paddingRight="14.0dip"
android:paddingTop="4.0dip"
android:textSize="16.0sp" /> <LinearLayout
android:id="@+id/send_layout"
android:layout_width="56.0dip"
android:layout_height="fill_parent"
android:layout_gravity="left|center"
android:clickable="true"
android:gravity="center_vertical" > <Button
android:id="@+id/send_btn"
android:layout_width="42.0dip"
android:layout_height="34.0dip"
android:layout_marginLeft="4.0dip"
android:background="@drawable/chat_bottombar_btn_selector"
android:enabled="false"
android:shadowColor="#ff568ab5"
android:shadowDx="0.0"
android:shadowDy="-1.0"
android:shadowRadius="0.2"
android:text="发送"
android:textColor="@color/send_btn_textcolor"
android:textSize="14.0sp" />
</LinearLayout>
</LinearLayout> <FrameLayout
android:id="@+id/panelLayout"
android:layout_width="fill_parent"
android:layout_height="204.0dip"
android:background="#ff34373c"
android:visibility="gone" > <GridView
android:id="@+id/panel"
android:layout_width="fill_parent"
android:layout_height="204.0dip"
android:gravity="center"
android:listSelector="#ff34373c"
android:numColumns="4"
android:paddingLeft="11.0dip"
android:paddingRight="11.0dip"
android:paddingTop="14.0dip"
android:scrollbars="none"
android:stretchMode="columnWidth"
android:verticalSpacing="14.0dip" /> <ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/chat_plugin_shadow" />
</FrameLayout> <LinearLayout
android:id="@+id/face_ll"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#fff0f0f0"
android:orientation="vertical"
android:paddingBottom="5dip"
android:paddingTop="5dip"
android:visibility="gone" > <com.org.view.JazzyViewPager
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/face_pager"
app:style="cubeout"
android:layout_width="fill_parent"
android:layout_height="120.0dip"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:background="#0000"
android:flipInterval="30"
android:persistentDrawingCache="animation" /> <com.org.view.CirclePageIndicator
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip" />
</LinearLayout> </LinearLayout>

还有很多适配器,其它实现效果的源代码就不具体贴了,须要细致研究,下载本文的源代码。

下载地址:点击

Android 聊天表情输入、表情翻页带效果、下拉刷新聊天记录的更多相关文章

  1. iOS聊天下拉刷新聊天记录的实现

    1. 想法 最近在开发一个社交类app,要实现类似微信那种下拉刷新聊天记录的功能. 一般有两种实现方式: 1. 直接fetch一个entity的所有数据然后在内存中做filter,就是把所有聊天记录先 ...

  2. [Swift通天遁地]二、表格表单-(4)使用系统自带的下拉刷新控件,制作表格的下拉刷新效果

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  3. Android零基础入门第72节:SwipeRefreshLayout下拉刷新

    在实际开发中,经常都会遇到下拉刷新.上拉加载更多的情形,这一期就一起来学习Android系统的SwipeRefreshLayout下拉刷新组件. 一.SwipeRefreshLayout简介 Swip ...

  4. Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理

    RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...

  5. 安卓ListView行详细内容展示页编写和下拉刷新实现

    ListView行详细内容展示页: 使用轻量级的Fragment实现Listview行内容简单的详细信息展示: 值得注意的是: 1. 主布局(打开它的Activity)必须是FrameLayout布局 ...

  6. Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向

    很多android应用的下拉刷新都是使用的pulltorefresh这个开源项目,但是它的扩展性在下拉刷新同时又上拉加载更多时会有一定的局限性.查了很多地方,发现这个开源项目并不能很好的同时支持下拉刷 ...

  7. .Net 转战 Android 4.4 日常笔记(10)--PullToRefresh下拉刷新使用

    下拉刷新很多地方都用到了,新浪微博,微信,百度新闻 这里我们使用一个开源的库叫:PullToRefresh 开源地址:https://github.com/chenyoca/pull-to-refre ...

  8. Android 学习笔记之AndBase框架学习(六) PullToRefrech 下拉刷新的实现

    PS:Struggle for a better future 学习内容: 1.PullToRefrech下拉刷新的实现...   不得不说AndBase这个开源框架确实是非常的强大..把大部分的东西 ...

  9. 下拉刷新控件(3)系统自带的下拉刷新控件SwipeRefreshLayout(推荐*)

    1,简介 The SwipeRefreshLayout should be used whenever the user can refresh the contents of a view via ...

随机推荐

  1. xfs文件备份恢复篇一vm中linux新增磁盘

    XFS提供了 xfsdump 和 xfsrestore 工具协助备份XFS文件系统中的数据.xfsdump 按inode顺序备份一个XFS文件系统.centos7选择xfs格式作为默认文件系统,而且不 ...

  2. flask 三剑客

    1.flask中的httpresponse @app.route("/") # app中的route装饰器 def index(): # 视图函数 return "Hel ...

  3. Patch 21352635 - Database Patch Set Update 11.2.0.4.8

    一.CPU和PSU 近日,将数据库从9.2.0.6升级到11.2.0.4后,发现11.2.0.4通过DBLINK访问其他的9i库时发生ORA-02072错误,通过Google找到解决方案,即升级到PS ...

  4. Python安装distribute包

    从官网https://pypi.python.org/pypi/distribute/0.6.49#downloads上下载distribute包,解压后进入解压文件的目录下,使用 python se ...

  5. 查看当前linux版本

    lsb_release -a 如果命令不存在,则yum安装 yum install redhat-lsb

  6. 转 IDEA 解决代码提示功能消失

    转载路径是  https://blog.csdn.net/hmily_hui/article/details/78213037 原文地址:https://github.com/Damao/Intell ...

  7. mongoDB 删除集合后,空间不释放的解决方法

    mongoDB 删除集合后,空间不释放,添加新集合,没有重新利用之前删除集合所空出来的空间,也就是数据库大小只增不减. 方法有: 1.导出导入 dump & restore 2.修复数据库 r ...

  8. 4星|《超级技术:改变未来社会和商业的技术趋势》:AI对人友好吗

    超级技术:改变未来社会和商业的技术趋势 多位专家或经济学人编辑关于未来的预测,梅琳达·盖茨写了其中一章.在同类书中属于水平比较高的,专家只写自己熟悉的领域,分析与预测有理有据而不仅仅是畅想性质. 以下 ...

  9. Cuder - 用C++11封装的CUDA类

    以前写cuda:初始化环境,申请显存,初始化显存,launch kernel,拷贝数据,释放显存.一个页面大部分都是这些繁杂但又必须的操作,有时还会忘掉释放部分显存. 今天用C++11封装了这些CUD ...

  10. [源码阅读]RocketMQ-策略篇

    一:为什么要阅读rocketmq的源码? 1 可以了解mq的底层实现逻辑. 二:打算怎么读,行动路径是哪儿些? 1: 本地启动 2 分步调试 3  fork项目,添加中文注释,提交到自己的代码库.并改 ...