【安卓笔记】气泡式ListView

实现效果:

要想实现这个效果,我们需要找到气泡背景的9.png图片,大家可以从qq微信等apk包中提取。

实现步骤:

1.编写布局文件。

每个条目的布局

activity_chat_singlemessage.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >
    <LinearLayout
        android:id="@+id/singleMessageContainer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
        <TextView
            android:id="@+id/singleMessage"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="5dip"
            android:background="@drawable/bubble_b"
            android:paddingLeft="10dip"
            android:textSize="18sp"
            android:text="Hello bubbles!"
            android:textColor="@android:color/primary_text_light" />
    </LinearLayout>
</LinearLayout>

界面布局:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <ListView
        android:id="@+id/listView1"
        android:divider="@null"
        android:listSelector="@android:color/transparent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="80dp" >
    </ListView>
    <RelativeLayout
        android:id="@+id/form"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:orientation="vertical" >
        <EditText
            android:id="@+id/chatText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_toLeftOf="@+id/buttonSend"
            android:ems="10"
            android:inputType="textMultiLine" />
        <Button
            android:id="@+id/buttonSend"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@+id/chatText"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:text="Send" />
    </RelativeLayout>
</RelativeLayout>

2.编写业务数据类:

package com.example.chatbubble;
public class ChatMessage {//代表每条消息
	public boolean left;//是否在左边
	public String message;

	public ChatMessage(boolean left, String message)
	{
		super();
		this.left = left;
		this.message = message;
	}
}

3.编写适配器类

package com.example.chatbubble;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ChatArrayAdapter extends ArrayAdapter<ChatMessage>
{
	private TextView chatText;
	private LinearLayout container;
	private List<ChatMessage> chatData = new ArrayList<>();

	@Override
	public void add(ChatMessage object)
	{
		chatData.add(object);
		super.add(object);
	}

	@Override
	public int getCount()
	{
		return chatData.size();
	}

	@Override
	public ChatMessage getItem(int position)
	{
		return chatData.get(position);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent)
	{
		if(convertView == null)
		{
			LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = inflater.inflate(R.layout.activity_chat_singlemessage,parent, false);
		}
		chatText = (TextView) convertView.findViewById(R.id.singleMessage);
		container = (LinearLayout) convertView.findViewById(R.id.singleMessageContainer);

		ChatMessage  msg = getItem(position);
		chatText.setText(msg.message);

		/*根据msg的内部left标识来判定应该选择什么背景,和位置(左/右)*/
		chatText.setBackgroundResource(msg.left ? R.drawable.bubble_b : R.drawable.bubble_a);
		container.setGravity(msg.left ? Gravity.LEFT : Gravity.RIGHT);

		return convertView;
	}

	public ChatArrayAdapter(Context context, int resource)
	{
		super(context, resource);
	}
}

4.编写主界面的代码:

package com.example.chatbubble;
import android.app.Activity;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class MainActivity extends Activity
{
	private ListView lv;
	private Button but;
	private EditText et;
	private ChatArrayAdapter adapter;
	private boolean side = false;
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		lv = (ListView) findViewById(R.id.listView1);
		but = (Button) findViewById(R.id.buttonSend);
		et = (EditText) findViewById(R.id.chatText);
		adapter = new ChatArrayAdapter(this,
				R.layout.activity_chat_singlemessage);
		lv.setAdapter(adapter);
		but.setOnClickListener(new OnClickListener()
		{
			@Override
			public void onClick(View v)
			{
				sendChatMessage();//发送消息
			}
		});

		lv.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
		//注册观察者,数据改变时滑到底部
		adapter.registerDataSetObserver(new DataSetObserver()
		{
			@Override
			public void onChanged()
			{
				super.onChanged();
				lv.setSelection(adapter.getCount() - 1);
			}
		});
	}
	private boolean sendChatMessage()
	{
		/*add方法内部会调用notifyDataSetChanged方法,故我们不需要手动调用!*/
		adapter.add(new ChatMessage(side, et.getText().toString()));
		/*清空数据*/
		et.setText("");
		side = !side;
		return true;
	}
}

效果完成!

源码地址:https://github.com/Rowandjj/BubbleStyleListViewDemo

时间: 2024-12-27 17:03:47

【安卓笔记】气泡式ListView的相关文章

【安卓笔记】抽屉式布局----DrawerLayout

效果如下: DrawerLayout来自support.v4包,所以不用考虑兼容性问题.其次,这种布局类似风靡一时的侧滑菜单,但是比侧滑菜单轻巧许多. 下面介绍这种布局的使用方式. 1.在你的项目中导入support.v4包. 2.编辑一个布局,根节点为android.support.v4.widget.DrawerLayout,此节点下只允许有两个子节点,第一个为将来主页面的内容,第二个节点即为"抽屉"内容,通常是一个ListView.比如: <android.support.

【安卓笔记】通过发送特定的短信远程控制手机

实现效果: 1.发送指令#*location*#,可以远程获取到手机的地理位置(经纬度),并以短信的形式返回. 2.发送指令#*locknow*#,可以远程锁屏并设置锁屏密码. 实现原理: 1.注册广播接受者,监听手机收到的短信,并对符合要求的特定短信进行拦截和处理. 2.通过LocationManager获取地理位置. 3.使用DevicePolicyManager实现锁屏.设置锁屏密码等操作. 步骤: 1.创建一个可以获取地理位置的工具类: package cn.edu.chd.mobile

【安卓笔记】仿猎豹清理大师波浪效果

先来看效果: 实现方式----->自定义控件 核心代码: package com.example.wavedemo1; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.os.Handler; import

【安卓笔记】在拨号界面通过拨打指定号码来启动某个秘密界面

方案说明: 1.通过注册广播接收者监听用户拨打电话操作: 2.当用户拨打电话时,广播接收者接收到号码,并与指定的"暗号"对比,若匹配,则启动某个界面并且终止用户拨打电话操作. 实现: 1.在清单文件中配置广播接收者,并添加权限: <receiver android:name="cn.edu.chd.mobilesafe.receiver.CallPhoneReceiver" > <intent-filter android:priority=&qu

【安卓笔记】快速开发设置界面-----PreferenceActivity

通常app都会有一个设置界面,如下: 通常做法是自己定义布局,然后在代码里面添加响应函数,并将结果保存到Sharedpreferences中. android给我们提供了PreferenceActivity来简化开发设置界面. 你只需这样做: 1.创建一个类继承PreferenceActivity,并导入设置界面布局: package com.example.preferenceactivitydemo1; import android.os.Bundle; import android.pre

【安卓笔记】切换图片(底部带有小点效果)

下面我们要实现这样的效果: 我们将采用两种方式实现这种效果: 1.使用ViewPager: 思路:ViewPager提供左右滑动图片操作的支持,下方小点在代码中动态创建,整个布局采用FrameLayout. 先看布局: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" and

安卓中去除ListView条目的分割线

现象 安卓中使用listview时条目与条目间会出现一条分割线,以前并没有在意过.今天仔细看了美工给出的效果图,条目间是没有分割线的.此处我们需要设置一下listview的属性 <ListView android:id="@+id/lv_ordertype" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marg

Xamrin开发安卓笔记(二)

安装篇 Xamrin开发安卓笔记(一) 昨天调理一天AAPT.EXE 被推出的问题(错误代码 error MSB6006: "aapt.exe" exited with code -1073741819),纠结一天到底是什么原因,寝食难安,后来想通了可能是安卓模拟器的原因.今早换了一个安卓SDK,到现在没出现AAPT的错误. 并且可以可视化布局(之前可视化布局很丑陋).然后接着写,暂时抛弃vs2015,因为2015的BUG直接影响我编写的感觉,所以先用vs2013 update4继续写

【安卓笔记】带自定义属性的view控件

开发中经常需要自定义view控件或者组合控件,某些控件可能需要一些额外的配置.比如自定义一个标题栏,你可能需要根据不同尺寸的手机定制不同长度的标题栏,或者更常见的你需要配置标题栏的背景,这时候,你就会考虑到你写的view的扩展性问题,通常情况下,我们可以为这个自定义的标题栏加上一些setXXX方法,供外界调用,设置其颜色.长度等属性.但是我们都知道,在使用系统控件时,我们大多数情况下并不需要在代码中配置控件,而仅仅只需在布局文件中对控件宽.高.颜色等进行配置,这样做的好处就将UI与业务逻辑解耦,

【安卓笔记】检测服务是否运行

/** * 判断服务是否后台运行 * * @param context * Context * @param className * 判断的服务名字 * @return true 在运行 false 不在运行 */ public static boolean isServiceRun(Context mContext, String className) { boolean isRun = false; ActivityManager activityManager = (ActivityMan