仿微信的语音聊天记录,左右两个布局

1.微信聊天记录是一个listview,并且分为自己和其他人的两个布局

1.1左侧为其他人的布局:

<?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:gravity="center_vertical"
    android:orientation="vertical" 
    android:background="#F5F5F5" >

    <TextView
        android:id="@+id/tv_voice_history_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#DCDCDC"
        android:gravity="center"
        android:layout_gravity="center_horizontal"
        android:minHeight="24dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="2016年09月02日  16:40:00"
        android:textColor="#fff"
        android:textSize="14dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingBottom="5dp"
        android:paddingTop="5dp">

        <ImageView
            android:id="@+id/iv_member_portrait"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginLeft="10dp"
            android:background="@drawable/member_info" />

        <LinearLayout
            android:id="@+id/ll_voice_play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_member_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="张星星"
                android:textColor="#a0a0a0"
                android:textSize="14dp"
                android:textStyle="normal" />

            <RelativeLayout
	            android:id="@+id/rl_voice_play"
	            android:visibility="visible"
	            android:layout_width="80dp"
	            android:layout_height="34dp"
	            android:focusable="false"
	            android:background="@drawable/selector_voice_history_bg"
            >

        <ImageView
                android:id="@+id/iv_voice_image_anim"
                android:layout_width="15dp"
                android:layout_height="20dp"
                android:background="@anim/voice_history_play_anim"
                android:layout_centerVertical="true"
                android:layout_marginLeft="18dp"
                android:visibility="gone"
                />

        <ImageView
            android:id="@+id/iv_voice_image"
            android:layout_width="15dp"
            android:layout_height="20dp"
            android:layout_centerVertical="true"
            android:layout_marginLeft="18dp"
            android:background="@drawable/sound_item"
            android:visibility="visible" />

    </RelativeLayout>
            
        </LinearLayout>

      
        
       
       <TextView
                android:id="@+id/tv_voice_duration"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:text="12 ''"
                android:textColor="#a0a0a0"
                android:textSize="16dp"
                android:textStyle="normal" />
       
        
    </LinearLayout>

</LinearLayout>


其中的动画是帧动画:

<?xml version="1.0" encoding="utf-8"?>
<animation-list  xmlns:android="http://schemas.android.com/apk/res/android"
                 android:oneshot="false">
    <item android:drawable="@drawable/sound_blank" android:duration="300"/>
    <item android:drawable="@drawable/sound_chat_send_one" android:duration="300"/>
    <item android:drawable="@drawable/sound_chat_send_two" android:duration="300"/>
    <item android:drawable="@drawable/sound_item" android:duration="300"/>

</animation-list>

1.2 右侧是自己的布局

<?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:gravity="center_vertical"
    android:orientation="vertical" 
    android:background="#F5F5F5" >

    <TextView
        android:id="@+id/tv_voice_history_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#DCDCDC"
        android:gravity="center"
        android:layout_gravity="center_horizontal"
        android:minHeight="24dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:text="2016年09月02日  16:40:00"
        android:textColor="#000" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingBottom="5dp"
        android:paddingTop="5dp">
        
        <View 
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="1dp"
            />
        
        <!-- <ImageView 
           android:id="@+id/iv_unread"
           android:layout_width="10dp"
           android:layout_height="10dp"
           android:layout_marginRight="10dp"
           android:background="@drawable/unread_message_circle_shape"
           /> -->
        
        <TextView
                android:id="@+id/tv_voice_duration"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="10dp"
                android:text="12 ''"
                android:textColor="#a0a0a0"
                android:textSize="16dp"
                android:textStyle="normal" />
        
        <LinearLayout
            android:id="@+id/ll_voice_play"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:gravity="right"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tv_member_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="我"
                android:textColor="#313131"
                android:textSize="18dp"
                android:textStyle="normal" />

            <RelativeLayout
	            android:id="@+id/rl_voice_play"
	            android:visibility="visible"
	            android:layout_width="80dp"
	            android:layout_height="34dp"
	            android:focusable="false"
	            android:gravity="right"
	            android:background="@drawable/selector_voice_history_bg_right"
            >

        <ImageView
                android:id="@+id/iv_voice_image_anim"
                android:layout_width="15dp"
                android:layout_height="20dp"
                android:layout_marginRight="18dp"
                android:background="@anim/voice_history_play_anim_right"
                android:layout_centerVertical="true"
                android:visibility="visible"
                />

        <ImageView
            android:id="@+id/iv_voice_image"
            android:layout_width="15dp"
            android:layout_height="20dp"
            android:layout_marginRight="18dp"
            android:layout_centerVertical="true"
            android:background="@drawable/sound_item_right"
            android:visibility="visible" />

    </RelativeLayout>
            
        </LinearLayout>

        <ImageView
            android:id="@+id/iv_member_portrait"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginRight="10dp"
            android:background="@drawable/member_info" />

        
    </LinearLayout>

</LinearLayout>

同样是帧动画,只是换成了沿Y轴对称的图片就行。


2.listview的adapter,adapter在填充布局的时候要选择用哪种布局,这里主要用到两个重写的方法getItemViewType()和getViewTypeCount();

/**
	 * 根据数据源的position返回需要显示的的layout的type
	 */
	@Override
	public int getItemViewType(int position) {
		
		Message msg = myList.get(position);
		int type = msg.getType();
		Log.e("TYPE:", ""+type);
		return type;
	}

	/**
	 * 返回所有的layout的数量
	 * 
	 * */
	@Override
	public int getViewTypeCount() {
		return 2;
	}

下面是我的完整的adapter类:

package com.example.listviewchatui;

import java.util.List;

import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * 想比较原来的多了getItemViewType和getViewTypeCount这两个方法,原来循环使用layout布局,起到了优化的作用
 */
public class MyAdapter extends BaseAdapter implements OnClickListener{

	
	public static final String KEY = "key";
	public static final String VALUE = "value";
	
	
	//因为在getViewTypeCount()方法中返回的是2,所以这两个值只能设置为0和1;切记,切记!否则会报角标越界的。
	public static final int VALUE_LEFT = 0;
	public static final int VALUE_RIGHT = 1;
	private LayoutInflater mInflater;
	
	private Context context;
	private List<Message> myList;
	private InterClick interClick;
	private int mPosition;
	private boolean isplaying;
	private boolean isSameItem;
	public MyAdapter(Context context, List<Message> myList, InterClick interClick){
		
		this.context = context;
		this.myList = myList;
		this.interClick = interClick;
		
		for(Message msg:myList){
			Log.d("myList:", msg.getType()+"");
		}
		
		mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	}
	
	public void addItem(final Message item) {
		myList.add(item);
        notifyDataSetChanged();
    }
	
	@Override
	public int getCount() {
		return myList.size();
	}

	@Override
	public Object getItem(int arg0) {
		return myList.get(arg0);
	}

	@Override
	public long getItemId(int arg0) {
		return arg0;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup arg2) {
		
		Message msg = myList.get(position);
		int type = getItemViewType(position);
		ViewHolder holder = null;
		
		if(convertView == null){
			holder = new ViewHolder();
			
				switch (type) {
								//左边
					case VALUE_LEFT:
						
						convertView = mInflater.inflate(R.layout.item_voice_history_left, null);
//						holder.tv_voice_history_time = (TextView)convertView.findViewById(R.id.tv_voice_history_time);
//						holder.tv_member_name = (TextView)convertView.findViewById(R.id.tv_member_name);
//						holder.tv_member_name.setText(msg.getValue());
//						holder.tv_voice_duration = (TextView)convertView.findViewById(R.id.tv_voice_duration);
//						holder.iv_voice_image = (ImageView)convertView.findViewById(R.id.iv_voice_image);
//						holder.iv_voice_image_anim = (ImageView)convertView.findViewById(R.id.iv_voice_image_anim);
						
						break;
						
								//右边
					case VALUE_RIGHT:
						
						convertView = mInflater.inflate(R.layout.item_voice_history_right, null);
//						holder.tv_voice_history_time = (TextView)convertView.findViewById(R.id.tv_voice_history_time);
//						holder.tv_member_name = (TextView)convertView.findViewById(R.id.tv_member_name);
//						holder.tv_member_name.setText(msg.getValue());
//						holder.tv_voice_duration = (TextView)convertView.findViewById(R.id.tv_voice_duration);
//						holder.iv_voice_image = (ImageView)convertView.findViewById(R.id.iv_voice_image);
//						holder.iv_voice_image_anim = (ImageView)convertView.findViewById(R.id.iv_voice_image_anim);
						
						break;
						
					default:
						break;
				}
				convertView.setTag(holder);
			}else{
				holder = (ViewHolder)convertView.getTag();
			}
		
		holder.tv_voice_history_time = (TextView)convertView.findViewById(R.id.tv_voice_history_time);
		holder.tv_member_name = (TextView)convertView.findViewById(R.id.tv_member_name);
		holder.tv_member_name.setText(msg.getValue());
		holder.tv_voice_duration = (TextView)convertView.findViewById(R.id.tv_voice_duration);
		holder.iv_voice_image = (ImageView)convertView.findViewById(R.id.iv_voice_image);
		holder.iv_voice_image_anim = (ImageView)convertView.findViewById(R.id.iv_voice_image_anim);
		holder.ll_voice_play = (LinearLayout)convertView.findViewById(R.id.ll_voice_play);
		
AnimationDrawable animationDrawable = (AnimationDrawable) holder.iv_voice_image_anim.getBackground();
		
		if (position == mPosition) {
			System.out.println("点击的条目======"+position);
			if (isSameItem) {
				if (isplaying) {
					holder.iv_voice_image.setVisibility(View.GONE);
					holder.iv_voice_image_anim.setVisibility(View.VISIBLE);
					animationDrawable.start();
				} else {
					holder.iv_voice_image_anim.setVisibility(View.GONE);
					holder.iv_voice_image.setVisibility(View.VISIBLE);
					animationDrawable.stop();
				}
			}else {
				animationDrawable.start();
				holder.iv_voice_image_anim.setVisibility(View.VISIBLE);
				holder.iv_voice_image.setVisibility(View.GONE);
			}
			
		}else {
			System.out.println("其它条目--------"+position);
			animationDrawable.stop();
			holder.iv_voice_image_anim.setVisibility(View.GONE);
			holder.iv_voice_image.setVisibility(View.VISIBLE);
		}
		
		holder.ll_voice_play.setOnClickListener(this);

		// 设置位置,获取点击的条目按钮
		holder.ll_voice_play.setTag(position);
		
			return convertView;
		}
	
	/**
	 * 根据数据源的position返回需要显示的的layout的type
	 */
	@Override
	public int getItemViewType(int position) {
		
		Message msg = myList.get(position);
		int type = msg.getType();
		Log.e("TYPE:", ""+type);
		return type;
	}

	/**
	 * 返回所有的layout的数量
	 * 
	 * */
	@Override
	public int getViewTypeCount() {
		return 2;
	}
	
	class ViewHolder{

		public LinearLayout ll_voice_play;
		public ImageView iv_voice_image_anim;
		public ImageView iv_voice_image;
		public TextView tv_voice_duration;
		public TextView tv_member_name;
		public TextView tv_voice_history_time;
	
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.ll_voice_play:
			interClick.animClick(v);
			break;
		default:
			break;
		}
	}

	public void refreshPersonContactsAdapter(int mPosition, boolean isplaying,
			boolean isSameItem) {
		this.mPosition = mPosition;
		this.isplaying = isplaying;
		this.isSameItem = isSameItem;
        notifyDataSetChanged(); 
	}

}

同样的里面也用到了接口,来实现语音播放时的动画效果,接口类如下:

package com.example.listviewchatui;

import android.view.View;

public interface InterClick {
	public void animClick(View v);
}


3.activity中为listview设置adapter,并监听条目中的按钮或布局的点击事件;

package com.example.listviewchatui;

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

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {

	private ListView lvData;
	private boolean isplaying;
	private boolean isSameItem;
	private int mPosition = -1;
	private int lastPosition = -1;
	private MyAdapter myAdapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		lvData = (ListView)findViewById(R.id.lv_data);
		
		lvData.setAdapter(getAdapter());
	}

	private BaseAdapter getAdapter(){
		myAdapter = new MyAdapter(this, getMyData(), interClick);
		return myAdapter;
	}
	
	private List<Message> getMyData(){
		
		List<Message> msgList = new ArrayList<Message>();
		Message msg;
		
		msg = new Message();
		msg.setType(MyAdapter.VALUE_LEFT);
		msg.setValue("别人");
			msgList.add(msg);
			
		msg = new Message();
		msg.setType(MyAdapter.VALUE_RIGHT);
		msg.setValue("自己");
			msgList.add(msg);
			
		msg = new Message();
		msg.setType(MyAdapter.VALUE_LEFT);
		msg.setValue("别人");
			msgList.add(msg);
			
		msg = new Message();
		msg.setType(MyAdapter.VALUE_RIGHT);
		msg.setValue("自己");
			msgList.add(msg);
		
			msg = new Message();
			msg.setType(MyAdapter.VALUE_LEFT);
			msg.setValue("别人");
			msgList.add(msg);
			
			msg = new Message();
			msg.setType(MyAdapter.VALUE_RIGHT);
			msg.setValue("自己");
			msgList.add(msg);
			
			msg = new Message();
			msg.setType(MyAdapter.VALUE_LEFT);
			msg.setValue("别人");
			msgList.add(msg);
			
			msg = new Message();
			msg.setType(MyAdapter.VALUE_RIGHT);
			msg.setValue("自己");
			msgList.add(msg);
			
			msg = new Message();
			msg.setType(MyAdapter.VALUE_LEFT);
			msg.setValue("别人");
			msgList.add(msg);
			
			msg = new Message();
			msg.setType(MyAdapter.VALUE_RIGHT);
			msg.setValue("自己");
			msgList.add(msg);
			
		return msgList;
		
	}
	
	private InterClick interClick = new InterClick() {
		@Override
		public void animClick(View v) {
			mPosition = (Integer) v.getTag();
			if (lastPosition == mPosition) {
				isSameItem = true;
				isplaying = !isplaying;
			} else {
				isSameItem = false;
				isplaying = true;
			}
			myAdapter.refreshPersonContactsAdapter(mPosition, isplaying, isSameItem);
			lastPosition = mPosition;
		}
	};
	
	
	
}

Message只是一个JavaBean对象,可以根据自己的需要设置对象。

这里只是写了2种不同的布局,更多详细的布局可以参考:http://blog.csdn.net/cleanness/article/details/24722403





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值