Android—简单的仿QQ聊天界面

摘要:
最近,我们基于QQ聊天创建了一个类似的界面。让我们先看看界面的组成。聊天背景可以是LinearLayout或存储在RelativeLayout中的ListView。所以我需要转到主界面的xml布局文件:完成后将出现下图:是时候为ListView设置条目了,这是我们聊天的消息!从图中,我们可以看到必须为ListView创建两个项目文件,气泡必须为.9png,否则将被扭曲。

最近仿照QQ聊天做了一个类似界面,先看下界面组成(画面不太美凑合凑合呗,,,,):

Android—简单的仿QQ聊天界面第1张

    其中聊天背景可以是一个LinearLayout或者RelativeLayout里面存放的是ListView(将ListView的分割线设置成透明:android:divider="#0000"否则聊天界面会显示出分割线,,,想想都屌,,,)

   于是,我要上主界面的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="match_parent"
    android:background="#c2c2c2"
    android:orientation="vertical"
    android:padding="16dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_horizontal_margin"
        android:layout_weight="1"
        android:background="@drawable/app_lvjian_rbtn_normal_background"
        android:orientation="vertical"
        android:padding="8dp" >

        <ListView
            android: 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="#0000"
            android:dividerHeight="8dp"
            android:scrollbars="none" >
        </ListView>
    </LinearLayout>
   

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="32dp"
        android:layout_marginTop="8dp"
        android:orientation="horizontal" >

        <EditText
            android: 
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:textSize="14sp"
            android:background="@drawable/app_lvjian_rbtn_normal_background"
            android:gravity="center|left"
            android:padding="8dp" />

        <Button
            android: 
             
            android:layout_width="64dp"
            android:layout_marginLeft="8dp"
            android:layout_height="match_parent"
            android:layout_gravity="center|right"
            android:layout_marginRight="4dp"
            android:background="@drawable/app_lvjian_chat_sends" />
    </LinearLayout>

</LinearLayout>

 完了就会出现下图:

Android—简单的仿QQ聊天界面第2张

于是该为ListView设置条目了,就是咱们聊天的消息了!

Android—简单的仿QQ聊天界面第3张

    由图可以看出要为ListView设置两个item文件,(头像和气泡的位置,方向,都不一样)其中气泡一定是.9png的否则会失真的。

    左边的item:

<?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="match_parent"
    android:orientation="horizontal" >

    <ImageView
        android: 
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_gravity="top"
        android:src="http://t.zoukankan.com/@drawable/app_lvjian_message_background" />

    <TextView
        android: 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:padding="8dp"
        android:background="@drawable/app_lvjian_other_chat_background"
        android:text="权志龙好帅!!!" />

</LinearLayout>

 右边的item

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <TextView
        android: 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dp"
        android:layout_marginTop="8dp"
        android:layout_toLeftOf="@+id/iv_chat_imagr_right"
        android:background="@drawable/app_lvjian_chat_right"
        android:padding="8dp"
        android:text="把那些贩毒的关到小黑屋,枪毙五十次,快去" />

    <ImageView
        android: 
        android:layout_width="24dp"
        android:layout_height="24dp"
        android:layout_alignParentRight="true"
        android:layout_gravity="top"
        android:src="http://t.zoukankan.com/@drawable/app_lvjian_message_background" />

</RelativeLayout>

     接下来还要为LiseView设置Adapter,发送消息时候有姓名,聊天内容等,我把这些元素封装了一个实体类先贴出来(Adapter会用到的):

package com.example.mychattext;

public class PersonChat {
	/**
	 * id
	 */
	private int id;
	/**
	 * 姓名
	 */
	private String name;
	/**
	 * 聊天内容
	 */
	private String chatMessage;
	/**
	 * 
	 * @return 是否为本人发送
	 */
    private boolean isMeSend;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getChatMessage() {
		return chatMessage;
	}
	public void setChatMessage(String chatMessage) {
		this.chatMessage = chatMessage;
	}
	public boolean isMeSend() {
		return isMeSend;
	}
	public void setMeSend(boolean isMeSend) {
		this.isMeSend = isMeSend;
	}
	public PersonChat(int id, String name, String chatMessage, boolean isMeSend) {
		super();
		this.id = id;
		this.name = name;
		this.chatMessage = chatMessage;
		this.isMeSend = isMeSend;
	}
	public PersonChat() {
		super();
	}
	

}

 自定义的Adapter加载布局文件的时候需要判断是哪方发送的消息来决定用哪个item布局文件,看Adapter:

package com.example.mychattext;

import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class ChatAdapter extends BaseAdapter {
	private Context context;
	private List<PersonChat> lists;

	public ChatAdapter(Context context, List<PersonChat> lists) {
		super();
		this.context = context;
		this.lists = lists;
	}

	/**
	 * 是否是自己发送的消息
	 * 
	 * @author cyf
	 * 
	 */
	public static interface IMsgViewType {
		int IMVT_COM_MSG = 0;// 收到对方的消息
		int IMVT_TO_MSG = 1;// 自己发送出去的消息
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return lists.size();
	}

	@Override
	public Object getItem(int arg0) {
		// TODO Auto-generated method stub
		return lists.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return arg0;
	}

	/**
	 * 得到Item的类型,是对方发过来的消息,还是自己发送出去的
	 */
	public int getItemViewType(int position) {
		PersonChat entity = lists.get(position);

		if (entity.isMeSend()) {// 收到的消息
			return IMsgViewType.IMVT_COM_MSG;
		} else {// 自己发送的消息
			return IMsgViewType.IMVT_TO_MSG;
		}
	}

	@Override
	public View getView(int arg0, View arg1, ViewGroup arg2) {
		// TODO Auto-generated method stub
		HolderView holderView = null;
		PersonChat entity = lists.get(arg0);
		boolean isMeSend = entity.isMeSend();
		if (holderView == null) {
			holderView = new HolderView();
			if (isMeSend) {
				arg1 = View.inflate(context, R.layout.chat_dialog_right_item,
						null);
				holderView.tv_chat_me_message = (TextView) arg1
						.findViewById(R.id.tv_chat_me_message);
				holderView.tv_chat_me_message.setText(entity.getChatMessage());
			} else {
				arg1 = View.inflate(context, R.layout.chat_dialog_left_item,
						null);

			}
			arg1.setTag(holderView);
		} else {
			holderView = (HolderView) arg1.getTag();
		}

		return arg1;
	}

	class HolderView {
		TextView tv_chat_me_message;
	}

	@Override
	public boolean isEnabled(int position) {
		return false;
	}
}

 区分消息发送方重点在IMsgViewType、getItemViewType、getView方法中,注释很详细,相信大家可以理解

最后是注释详细的MAinActivity:

package com.example.mychattext;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
	private ChatAdapter chatAdapter;
	/**
	 * 声明ListView
	 */
	private ListView lv_chat_dialog;
	/**
	 * 集合
	 */
	private List<PersonChat> personChats = new ArrayList<PersonChat>();
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			int what = msg.what;
			switch (what) {
			case 1:
				/**
				 * ListView条目控制在最后一行
				 */
				lv_chat_dialog.setSelection(personChats.size());
				break;

			default:
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		/**
		 * 虚拟4条发送方的消息
		 */
		for (int i = 0; i <= 3; i++) {
			PersonChat personChat = new PersonChat();
			personChat.setMeSend(false);
			personChats.add(personChat);
		}
		lv_chat_dialog = (ListView) findViewById(R.id.lv_chat_dialog);
		Button btn_chat_message_send = (Button) findViewById(R.id.btn_chat_message_send);
		final EditText et_chat_message = (EditText) findViewById(R.id.et_chat_message);
		/**
		 *setAdapter
		 */
		chatAdapter = new ChatAdapter(this, personChats);
		lv_chat_dialog.setAdapter(chatAdapter);
		/**
		 * 发送按钮的点击事件
		 */
		btn_chat_message_send.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				// TODO Auto-generated method stub
				if (TextUtils.isEmpty(et_chat_message.getText().toString())) {
					Toast.makeText(MainActivity.this, "发送内容不能为空", 0).show();
					return;
				}
				PersonChat personChat = new PersonChat();
				//代表自己发送
				personChat.setMeSend(true);
				//得到发送内容
				personChat.setChatMessage(et_chat_message.getText().toString());
				//加入集合
				personChats.add(personChat);
				//清空输入框
				et_chat_message.setText("");
				//刷新ListView
				chatAdapter.notifyDataSetChanged();
				handler.sendEmptyMessage(1);
			}
		});
	}

}

 源码连接:http://pan.baidu.com/s/1dF9Rcrv

免责声明:文章转载自《Android—简单的仿QQ聊天界面》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇UNIAPP 离线打包 ANDROID APKAndroid游戏开发教程之六:自定义View详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

HBuilder ,及自用主题

字体:Consolas http://bbs.csdn.net/topics/390858585   让代码更美:你最爱的编程字体 http://www.dcloud.io     HBuilder下载 http://ask.dcloud.net.cn/docs  文档 http://www.dcloud.io/readme/#title12    nat...

第一行代码

基本布局 线性布局:LinearLayout android:orientation:指定排列的方向,参数:vertical/horizontal。不指定时,默认的排列方向是horizontal。 android:layout_gravity:指定控件在布局的对齐方式。可以用“|”分割,同时指定多个参数。 注意: 排列方向为horizontal时...

ORA-01089 数据库无法正常关闭

今天在做SOA几个数据库的重启操作,其中一个数据库在关闭过程中一直处于HANG住状态,十几分钟没有任何进展,具体操作过程如下: 一:当时的情景 SQL> shutdown immediate      --无任何返回结果 二:问题定位过程 1.查询相关进程只有ORACLE的关键进程存在    ps -ef |grep ora_    soadb  4...

通过案例理解position:relative和position:absolute

w3school过了HTML的知识之后,觉得要自己单纯地去啃知识点有点枯燥,然后自己也很容易忘记,所以便找具体的网站练手便补上不懂的知识点。position:relative和postion:absolute困扰了我快一个星期之久,网上找到的资料鱼龙混杂,刚确定“这样”的理解之后,看另一份资料,发现“这样”理解是错了,就这样不断更正,并记录下来,最终整理出...

MAC 上找不到.bash_profile或者ect/profile该怎么办?

     开发Android的环境要重新在Mac上搭建,结果在配置环境变量时找不到.bash_profile文件。查过很多资料解决方案都很笼统,结果还是在英文网站上找到解决方法。 1. 启动终端Terminal 2. 进入当前用户的home目录     输入cd ~ 3. 创建.bash_profile     输入touch .bash_profi...

CSS布局之display: tables布局

首先来看看display: table的兼容性: 可以看到,除非你还要跟IE6/7较劲,否则display: table不需考虑兼容性。 接下来看看关于table的display可选值: table:指定对象作为块元素级的表格,相当于html标签<table> inline-table:指定对象作为内联元素级的表格,相当于html标签&l...