1. 自定义标题栏。(标题栏不做任何功能)
2. 有左右发送按钮。(这个只能自己和自己聊天哦,所以有左右发送按钮)
(1)点击左边按钮发送按钮,在ListView的左侧显示。
(2)点击右边按钮发送按钮,在ListView的右侧显示。
3.有表情发送按钮。
(1)当点击表情发送按钮时, 弹出表情框,点击想要发送的表情将其添加输入框中。
(2)当在此点击表情按钮时,表情框收回。
(3)当表情框处在显示状态时, 点击输入框时,表情框收回。
聊天界面的制作(一)——基本布局的实现
聊天界面的制作(二)——发送消息后ListView左右布局显示
源码下载链接
1. 在总布局中添加一个GridView控件,用于显示表情列表。控件中设置一个android:visibility="gone"
让其不显示且不占用空间。当点击表情按钮时才显示,也就是将其值在设置为”visible”;当在次点击时,不显示表情框,也就是又将其值设置为”gone”。
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<include
android:id="@+id/title_bar"
layout="@layout/title_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/chatting_background"
android:listSelector="@android:color/transparent">ListView>
<LinearLayout
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/grey"
android:gravity="bottom"
android:orientation="horizontal">
<ImageButton
android:id="@+id/imagebutton_expression"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="10dp"
android:focusable="true"
android:background="@drawable/imagebutton_expression" />
<Button
android:id="@+id/button_left"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_margin="5dp"
android:background="@drawable/button_send_background"
android:padding="5dp"
android:text="发送"
android:textColor="@color/white" />
<EditText
android:id="@+id/edittext_input"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_weight="1"
android:background="@drawable/edittext_background"
android:padding="7dp"
android:layout_gravity="center"/>
<Button
android:id="@+id/button_right"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_margin="5dp"
android:background="@drawable/button_send_background"
android:padding="5dp"
android:text="发送"
android:textColor="@color/white" />
LinearLayout>
<GridView
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="7"
android:visibility="visible"
android:background="@color/grey">
GridView>
LinearLayout>
2. 首先定义一个布局,用于在GridView中的Item中显示每一个表情。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/imageview_expression"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:src="@mipmap/dra" />
LinearLayout>
定义ExpressionAdapter将表情数据添加到布局中。
public class ExpressionAdapter extends BaseAdapter {
//表情数据
private int[] mExpression = {R.mipmap.dra,R.mipmap.drb,R.mipmap.drc,R.mipmap.drd,R.mipmap.dre,R.mipmap.drf,R.mipmap.drg,
R.mipmap.drh,R.mipmap.dri,R.mipmap.drj,R.mipmap.drk,R.mipmap.drl,R.mipmap.drm,R.mipmap.drn,
R.mipmap.dro,R.mipmap.drp,R.mipmap.drq,R.mipmap.drr,R.mipmap.drs,R.mipmap.drt,R.mipmap.dru,
R.mipmap.drv,R.mipmap.drw,R.mipmap.drx,R.mipmap.dry,R.mipmap.drz,R.mipmap.dra};
private LayoutInflater mInflater;
public ExpressionAdapter(LayoutInflater mInflater) {
this.mInflater = mInflater;
}
@Override
public int getCount() {
return mExpression.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
ViewHolder viewHolder = null;
if(convertView == null){
convertView = mInflater.inflate(R.layout.item_expression, null);
viewHolder = new ViewHolder();
viewHolder.imageview = (ImageView) convertView.findViewById(R.id.imageview_expression);
convertView.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.imageview.setImageResource(mExpression[position]);
return convertView;
}
class ViewHolder{
ImageView imageview;
}
}
3. 定义一个富文本,富文本中需要创建ImageGetter对象。然后通过Spanned对象ImageGetter对象返回的id来获得图片。
public class MainActivity extends Activity implements View.OnClickListener {
private Button mButtonLeft;//左边发送按钮
private Button mButtonRight;//右边发送按钮
private EditText mEditTextInput;//输入框
private ListView mListView;//显示消息的ListView
private GridView mGridView;//显示表情的GridView
private ImageButton mImageButtonExpression;//弹出和收回表情框的按钮
private Spanned mSpanned;//富文本
private Html.ImageGetter mImageGetter;//获得富文本图片
private List mData;//消息数据
private MessageAdapter mMessageAdapter;//消息适配器
private ExpressionAdapter mExpressionAdapter;//表情适配器
private InputMethodManager mInputMethodManager;//用于控制手机键盘的显示有否的对象(此处)
//表情数据名称
private String[] mExpression = {"dra", "drb", "drc", "drd", "dre", "drf",
"drg", "drh", "dri", "drg", "drk", "drl",
"drm", "drn", "dro", "drp", "drq", "drr",
"drs", "drt", "dru", "drv", "drw", "drx",
"dry", "drz", "dra"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonLeft = (Button) findViewById(R.id.button_left);
mButtonRight = (Button) findViewById(R.id.button_right);
mEditTextInput = (EditText) findViewById(R.id.edittext_input);
mImageButtonExpression = (ImageButton) findViewById(R.id.imagebutton_expression);
mListView = (ListView) findViewById(R.id.listview);
mGridView = (GridView) findViewById(R.id.gridview);
mButtonLeft.setOnClickListener(this);
mButtonRight.setOnClickListener(this);
mImageButtonExpression.setOnClickListener(this);
mInputMethodManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
//消息数据初始化
mData = new ArrayList();
//通过反射获得图片的id
mImageGetter = new Html.ImageGetter() {
@Override
public Drawable getDrawable(String s) {
Drawable drawable = null;
int id = R.mipmap.dra;
if (s != null) {
Class clazz = R.mipmap.class;
try {
Field field = clazz.getDeclaredField(s);
id = field.getInt(s);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
drawable = getResources().getDrawable(id);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
return drawable;
}
};
mExpressionAdapter = new ExpressionAdapter(getLayoutInflater());
mGridView.setAdapter(mExpressionAdapter);
//点击表情,将表情添加到输入框中。
mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int position, long l) {
//通过mImageGetter获得id获得表情图片,然后将其添加到输入框中。
mSpanned = Html.fromHtml("", mImageGetter, null);
mEditTextInput.getText().insert(mEditTextInput.getSelectionStart(), mSpanned);
}
});
//点击输入框收回表情框
mEditTextInput.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mGridView.getVisibility() == View.VISIBLE) {
mGridView.setVisibility(View.GONE);
}
}
});
}
@Override
public void onClick(View view) {
mMessageAdapter = new MessageAdapter(getLayoutInflater(), mData, mImageGetter);
switch (view.getId()) {
case R.id.imagebutton_expression://添加表情的按钮
if (mGridView.getVisibility() == View.VISIBLE) {
mGridView.setVisibility(View.GONE);
} else {
mGridView.setVisibility(View.VISIBLE);
mInputMethodManager.hideSoftInputFromWindow(mEditTextInput.getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS);
}
break;
case R.id.button_left://左边的发送按钮
showListViewLeft();
break;
case R.id.button_right://右边的发送按钮
showListViewRight();
break;
default:
break;
}
}
/*
发送左边消息
*/
private void showListViewRight() {
ChatMessage dataRight = new ChatMessage();
dataRight.setTextViewTime(System.currentTimeMillis());
dataRight.setTextViewHonour("营长");
dataRight.setTextviewName("虫虫");
/*
判断发送的消息是否为空,如果为空则弹出提示不允许发送
*/
if (filterHtml(Html.toHtml(mEditTextInput.getText())).equals("")) {
Toast.makeText(getApplicationContext(), "发送的消息不能为空!", Toast.LENGTH_SHORT).show();
return;
}
dataRight.setTextViewInput(filterHtml(Html.toHtml(mEditTextInput.getText())));
dataRight.setType(MessageAdapter.SEND_RIGHT);
mMessageAdapter.notifyDataSetChanged();
mData.add(dataRight);
mListView.setAdapter(mMessageAdapter);
mListView.setSelection(mData.size() - 1);
mEditTextInput.setText("");
}
/*
发送右边消息
*/
private void showListViewLeft() {
ChatMessage dataLeft = new ChatMessage();
dataLeft.setTextViewTime(System.currentTimeMillis());
dataLeft.setTextViewHonour("营长");
dataLeft.setTextviewName("虫虫");
/*
判断发送的消息是否为空,如果为空则弹出提示不允许发送
*/
if (filterHtml(Html.toHtml(mEditTextInput.getText())).equals("")) {
Toast.makeText(getApplicationContext(), "发送的消息不能为空!", Toast.LENGTH_SHORT).show();
return;
}
//将解析的数据添加到输入框中。
dataLeft.setTextViewInput(filterHtml(Html.toHtml(mEditTextInput.getText())));
dataLeft.setType(MessageAdapter.SEND_LEFT);
mMessageAdapter.notifyDataSetChanged();
mData.add(dataLeft);
mListView.setAdapter(mMessageAdapter);
mListView.setSelection(mData.size() - 1);
mEditTextInput.setText("");
}
public String filterHtml(String str) {
str = str.replaceAll("<(?!br|img)[^>]+>", "").trim();
return str;
}
}
聊天界面在点击表情按钮时会收回手机输入法键盘,在模拟器中无法演示,在此说明下。