• Android—简单的仿QQ聊天界面


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

        其中聊天背景可以是一个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:id="@+id/lv_chat_dialog"
                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:id="@+id/et_chat_message"
                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:id="@+id/btn_chat_message_send"
                style="?android:attr/buttonStyleSmall"
                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>
    

     完了就会出现下图:

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

        由图可以看出要为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:id="@+id/ivicon"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_gravity="top"
            android:src="@drawable/app_lvjian_message_background" />
    
        <TextView
            android:id="@+id/tvname"
            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:id="@+id/tv_chat_me_message"
            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:id="@+id/iv_chat_imagr_right"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_alignParentRight="true"
            android:layout_gravity="top"
            android:src="@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

  • 相关阅读:
    【笔记】 寻址方式
    今日思考之 20200614:java 中 null 是否对 gc 有帮助?
    分布式唯一ID生成方案对比分析 笔记
    请不要再称数据库是CP或者AP——CAP的误导(短板)和它的使命
    延迟初始化中的 双重检查模式 和 延迟占位类模式 你都用对了吗?
    redis bitmap
    RabbitMQ 使用 Policies HTTP API 绑定和解绑 DLX
    spring boot 自动装配的实现原理和骚操作,不同版本实现细节,debug 到裂开......
    netty 学习笔记三:大跃进,使用 netty 实现 IM 即时通讯系统
    一道 Java 方法传值面试题——Java方法传值的值传递概念和效果 + Integer 缓存机制 + 反射修改 private final 域
  • 原文地址:https://www.cnblogs.com/yunfang/p/5553629.html
Copyright © 2020-2023  润新知