1.简单介绍:

ListView是android开发中经常使用的控件,系统自带的那些样式,我就不列举了。

今天主要看一下。一个模仿系统历史通话记录的ListView。

效果例如以下:

上面ListView的样式还能够更复杂。首先看一下这个简单的ListView的Item的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contacts_items"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:orientation="vertical" > <View
android:id="@+id/topLine"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#ff474745" /> <RelativeLayout
android:layout_width="fill_parent"
android:layout_height="60dp"
android:gravity="center_vertical"
android:paddingRight="1.0dip" > <LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal" > <ImageView
android:id="@+id/imgHead"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginLeft="15dp"
android:layout_marginRight="10dp"
android:contentDescription="" /> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="vertical" > <TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:singleLine="true"
android:textSize="14.0sp" /> <TextView
android:id="@+id/tvTelephone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="4.0dip"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ffcccccc"
android:textSize="12sp" /> <TextView
android:id="@+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="0.2dip"
android:layout_marginTop="0dip"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ffcccccc"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout> <LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal" > <Button
android:id="@+id/btnCall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="0.2dip"
android:layout_marginTop="0dip"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#ff0000ff"
android:focusable="false"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout> <View
android:id="@+id/bottomLine"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#ff1c1c1b" /> <View
android:id="@+id/lastLine"
android:layout_width="fill_parent"
android:layout_height="1dp"
android:background="#ff474745"
android:visibility="gone" /> </LinearLayout>

没什么问题吧?可是你一定要注意Button的一个属性:android:focusable="false",假设不加这个属性,会使得ListView的OnItemClick被屏蔽。

因为是模仿通话记录,那么Item里面的这个属性。我们还是封装到一个类里面吧。

/*
* $filename: Model.java,v $
* $Date: 2014-4-27 $
* Copyright (C) ZhengHaibo, Inc. All rights reserved.
* This software is Made by Zhenghaibo.
*/
package com.example.testaa; import org.androidannotations.annotations.EBean; /*
*@author: ZhengHaibo
*web: http://blog.csdn.net/nuptboyzhb
*mail: zhb931706659@126.com
*2014-4-27 Nanjing,njupt,China
*/
@EBean
public class Model {
private int imgHead;//头像资源ID
private String name;//姓名
private String telephone;//电话号码
private String date;//日期
public int getImgHead() {
return imgHead;
}
public void setImgHead(int imgHead) {
this.imgHead = imgHead;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTelephone() {
return telephone;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
} }

接下来。思路非常清晰。就是继承BaseAdapter类,重写它的几个重要方法:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
return null;
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
} @Override
public int getCount() {
// TODO Auto-generated method stub
return 0;
}

依照我们的需求,我们必须在getView类中,为Item布局中的每个View进行关联。设置对应的參数。而对于Button,还要设置对应的事件监听器。我们必须注意的是:在设置事件监听器的时候。我们必须将当前的Item的位置信息position传递给监听器。否则的话,onClick方法无法知道当前按下的是哪个button。因此,我们写了一个内部类,实现OnClickListener接口,这个类的须要有一个属性来保存Item的位置。

因此,我们的BaseAdapter1代码例如以下:

/*
* $filename: BaseAdapter1.java,v $
* $Date: 2014-4-27 $
* Copyright (C) ZhengHaibo, Inc. All rights reserved.
* This software is Made by Zhenghaibo.
*/
package com.example.testaa; import java.util.ArrayList;
import java.util.List; import android.content.Context;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast; /*
*@author: ZhengHaibo
*web: http://blog.csdn.net/nuptboyzhb
*mail: zhb931706659@126.com
*2014-4-27 Nanjing,njupt,China
*/
public class BaseAdapter1 extends BaseAdapter { private Context context; private List<Model> listViewData; private int layoutResId;//ListView每个Item的布局文件 public BaseAdapter1(Context context,int layoutResId) {
this.context = context;
this.layoutResId = layoutResId;
listViewData = new ArrayList<Model>();
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(context).inflate(layoutResId,null);
Model model = listViewData.get(position);
ImageView imageView = (ImageView)convertView.findViewById(R.id.imgHead);
imageView.setImageBitmap(BitmapFactory.decodeResource(context.getResources(), model.getImgHead()));
TextView tvName = (TextView)convertView.findViewById(R.id.tvName);
tvName.setText(model.getName());
TextView tvTelephone = (TextView)convertView.findViewById(R.id.tvTelephone);
tvTelephone.setText(model.getTelephone());
TextView tvDate = (TextView)convertView.findViewById(R.id.tvDate);
tvDate.setText(model.getDate());
Button btnCall = (Button) convertView.findViewById(R.id.btnCall);
btnCall.setText("拨打电话");
btnCall.setOnClickListener(new ListViewButtonOnClickListener(position) );
return convertView;
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return listViewData.get(position);
} @Override
public int getCount() {
// TODO Auto-generated method stub
if(null == listViewData){
return 0;
}
return listViewData.size();
} /**
* 加入一条记录
* @param model
*/
public void addModel(Model model){
listViewData.add(model);
}
/**
* 获取一条记录
* @param i
* @return
*/
public Model getModel(int i){
if(i<0||i>listViewData.size()-1){
return null;
}
return listViewData.get(i);
}
/**
* 清除全部数据
*/
public void clear(){
listViewData.clear();
} class ListViewButtonOnClickListener implements OnClickListener{
private int position;//记录ListView中Button所在的Item的位置
public ListViewButtonOnClickListener(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
Toast.makeText(context,listViewData.get(position).getTelephone(), Toast.LENGTH_SHORT).show();
}
}
}

由此可见,假设我们须要定制Item的布局,我们仅仅须要改动的地方除了Item的布局文件以外,还要将Adapter里的getView方法进行对应的改动。

接下来看一下Activity的測试代码

package com.example.testaa;

import java.text.SimpleDateFormat;
import java.util.Date; import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById; import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
@EActivity(R.layout.activity_list_1)
public class ActivityList1 extends Activity implements OnItemClickListener{ @ViewById
ListView listView;
//ListView的设配器
private BaseAdapter1 baseAdapter1;
@AfterViews
void afterViewInitList(){
baseAdapter1 = new BaseAdapter1(this,R.layout.listview1);
listView.setAdapter(baseAdapter1);
listView.setOnItemClickListener(this);
for(int i=0;i<10;i++){
Model model = new Model();
model.setImgHead(R.drawable.ic_launcher);
model.setName("Name"+i);
model.setTelephone("手机 1311111111"+i);
model.setDate(new SimpleDateFormat().format(new Date()).toString());
baseAdapter1.addModel(model);
}
baseAdapter1.notifyDataSetChanged(); }
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
// TODO Auto-generated method stub
Log.d("ItemClick", "pos="+position);
String string = "clicked item"+position+"content="+baseAdapter1.getModel(position).getTelephone();
Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
}
}

此时。就完毕了我们想要的功能。

Item的点击事件和Button的点击事件互不冲突。

问题二:

向微信,QQ,易信等聊天界面的ListView则有所不同。

我们上述的样例是:Item仅仅有一个布局。而聊天界面其中ListView的Item布局有多种,比方显示文字的布局,显示图片的布局,显示语音的布局等等。除此之外。我们还要依据消息的发送者,将其左右分开。在这里,仅仅演示左右的文本。原理都是都是一样的。

先看一下布局文件

左右文本的布局文件:

<RelativeLayout 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"
> <ImageView
android:id="@+id/imgHead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_margin="5dip"
android:src="@drawable/ic_launcher"
/> <Button
android:id="@+id/btn_left_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/imgHead"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:textColor="#404040"
android:textSize="16sp"
android:gravity="center"
android:focusable="false"
android:background="@drawable/chatfrom_bg_normal"
/> </RelativeLayout>

右边的布局文件:

<RelativeLayout 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"
> <ImageView
android:id="@+id/imgHead"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_margin="5dip"
android:src="@drawable/ic_launcher"
/> <Button
android:id="@+id/btn_right_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/imgHead"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:textColor="#404040"
android:textSize="16sp"
android:gravity="center"
android:focusable="false"
android:background="@drawable/chatto_bg_normal"
/> </RelativeLayout>

再看一下适配器,基本和上一个样例一样,不一样无非就是getView方法的差异。

/*
* $filename: BaseAdapter1.java,v $
* $Date: 2014-4-27 $
* Copyright (C) ZhengHaibo, Inc. All rights reserved.
* This software is Made by Zhenghaibo.
*/
package com.example.testaa; import java.util.ArrayList;
import java.util.List; import android.content.Context;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast; /*
*@author: ZhengHaibo
*web: http://blog.csdn.net/nuptboyzhb
*mail: zhb931706659@126.com
*2014-4-27 Nanjing,njupt,China
*/
public class ChatBaseAdapter extends BaseAdapter { private Context context; private List<Msg> listViewData; public ChatBaseAdapter(Context context) {
this.context = context;
listViewData = new ArrayList<Msg>();
} /**
* 依据发送消息的类型进行分类,不同的消息类型不同的布局
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Msg msg = listViewData.get(position);
if(msg.isSelf()){//自己发送的消息
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_right_text,null);
ImageView imgHead =(ImageView) convertView.findViewById(R.id.imgHead);
imgHead.setImageBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher));
Button btn = (Button)convertView.findViewById(R.id.btn_right_text);
btn.setText(msg.getContent());
btn.setOnClickListener(new ListViewButtonOnClickListener(position));
}else {//对方发送的消息
convertView = LayoutInflater.from(context).inflate(R.layout.list_item_left_text,null);
ImageView imgHead =(ImageView) convertView.findViewById(R.id.imgHead);
imgHead.setImageBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher));
Button btn = (Button)convertView.findViewById(R.id.btn_left_text);
btn.setText(msg.getContent());
btn.setOnClickListener(new ListViewButtonOnClickListener(position));
}
return convertView;
} @Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
} @Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return listViewData.get(position);
} @Override
public int getCount() {
// TODO Auto-generated method stub
if(null == listViewData){
return 0;
}
return listViewData.size();
} /**
* 加入一条记录
* @param Msg
*/
public void addMsg(Msg Msg){
listViewData.add(Msg);
}
/**
* 获取一条记录
* @param i
* @return
*/
public Msg getMsg(int i){
if(i<0||i>listViewData.size()-1){
return null;
}
return listViewData.get(i);
}
/**
* 清除全部数据
*/
public void clear(){
listViewData.clear();
} class ListViewButtonOnClickListener implements OnClickListener{
private int position;//记录ListView中Button所在的Item的位置
public ListViewButtonOnClickListener(int position) {
this.position = position;
}
@Override
public void onClick(View v) {
Toast.makeText(context,listViewData.get(position).getContent(), Toast.LENGTH_SHORT).show();
}
}
}

Activity的代码为:

package com.example.testaa;

import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById; import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;
@EActivity(R.layout.activity_list_2)
public class ActivityList2 extends Activity implements OnItemClickListener{ @ViewById
ListView listView; private ChatBaseAdapter chatBaseAdapter;
@AfterViews
void afterViewInitList(){
chatBaseAdapter = new ChatBaseAdapter(this);
listView.setAdapter(chatBaseAdapter);
listView.setOnItemClickListener(this);
for(int i=0;i<10;i++){
Msg msg = new Msg();
if(i%2==0){
msg.setSelf(false);
}else {
msg.setSelf(true);
}
msg.setContent("abc"+i);
chatBaseAdapter.addMsg(msg);
}
chatBaseAdapter.notifyDataSetChanged(); }
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
// TODO Auto-generated method stub
Log.d("ItemClick", "pos="+position);
String string = "clicked item"+position+"content="+chatBaseAdapter.getMsg(position).getContent();
Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
}
}

效果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbnVwdDEyMzQ1Njc4OQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

关于聊天界面的很多其它内容可參考博文:http://blog.csdn.net/xyz_lmn/article/details/13745489

原理基本一样。

注意:整个项目的代码使用的是AndroidAnnotation框架,本博客的代码下载:http://download.csdn.net/detail/nuptboyzhb/7260915

ListView布局之View复用原理举例的更多相关文章

  1. 深入了解View实现原理以及自定义View详解

    下面几篇文章对View的原理讲的非常详细. Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了解View(二) ...

  2. 【我的Android进阶之旅】如何去除ListView中Header View、Footer View中的分割线

    最近的项目中给ListView 加入了一个Header View之后,发现Header View的下方也有了分割线,很难看,UI要求将Header View的分割器去掉,好吧.现在就来说一说如何如何去 ...

  3. 转:ListView中getView的工作原理

    ListView中getView的工作原理: [1]ListView asks adapter “give me a view” (getView) for each item of the list ...

  4. Atitit.java c#.net php项目中的view复用(jsp,aspx,php的复用)

    Atitit.java c#.net php项目中的view复用(jsp,aspx,php的复用) 1.1. Keyword1 1.2. 前言1 2. Java项目使用.Net的aspx页面view1 ...

  5. Android View绘制原理分析

    推荐两篇分析view绘制原理比较好的文章,感谢作者的分享. <Android应用层View绘制流程与源码分析> <View 绘制流程>

  6. [转载]ExtJs4 笔记(11) Ext.ListView、Ext.view.View 数据视图

    本篇介绍两个用来展示数据的容器控件,分别是Ext.ListView和Ext.view.View.Ext.ListView就是大名鼎鼎的 Ext GridPanel的前身,不过现在的Ext4已经将它整合 ...

  7. Android自定义View研究--View中的原点坐标和XML中布局自定义View时View触摸原点问题

    这里只做个汇总~.~独一无二 文章出处:http://blog.csdn.net/djy1992/article/details/9715047 Android自定义View研究--View中的原点坐 ...

  8. ExtJs4 笔记(11) Ext.ListView、Ext.view.View 数据视图

    本篇介绍两个用来展示数据的容器控件,分别是Ext.ListView和Ext.view.View.Ext.ListView就是大名鼎鼎的Ext GridPanel的前身,不过现在的Ext4已经将它整合到 ...

  9. android listView布局等分列

    android listView布局4等分列. 必须要加上<RelativeLayout 在外层,不然等分不起作用 <RelativeLayout xmlns:android=" ...

随机推荐

  1. Typora——自定义设置

    Typora提供自定义设置,在偏好设置里面,有一个主题文件夹,如果对界面的样式进行设定,可以添加一个css文件,命名规范是 github.user.css,下面代码会对h1~h4进行自动序列化 bod ...

  2. 4星|《OKR工作法》:关注公司的真正目标,以周为单位做计划和考核

    本书篇幅比较小,两个小时就可以看完.主要内容讲OKR工作法的基本概念,然后用一个虚拟的创业公司的创业故事来演示实施OKR过程中可能遇到的问题.OKR给创业带来的好处. OKR工作法相对来说是比较简单的 ...

  3. 史上最大型广告欺诈活动Methbot:黑客是如何每天赚到500万美元的

    根据国外安全专家的最新报告,有一群黑客正在对美国的知名企业和媒体机构进行广告欺诈活动,而这群黑客每天都可以从中赚取三百万到五百万美金. 是的,你没看错,这绝对是人类历史上最牛X的恶意广告欺诈活动!不过 ...

  4. 机器学习_K近邻Python代码详解

    k近邻优点:精度高.对异常值不敏感.无数据输入假定:k近邻缺点:计算复杂度高.空间复杂度高 import numpy as npimport operatorfrom os import listdi ...

  5. Mybatis学习总结三(动态SQL)

    通过mybatis提供的各种标签方法实现动态拼接sql. 一.if 和 where <select id="findUserList" parameterType=" ...

  6. block的作用

    ios高效开发--blocks相关   1.替换delegate       如果我们有2个viewController,a和b,当我们从a界面push到b后,在b上面触发了一些事件,这些时间又会影响 ...

  7. response对象设置输出缓冲大小

    response对象设置输出缓冲大小 制作人:全心全意 通常情况下,服务器要输出到客户端的内容不会直接写到客户端,而是先写到一个输出缓冲区,在计算机术语中,缓冲区被定义为暂时放置输入或输出资料的内存. ...

  8. Django DTL模板语法中的判断

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. saltstack(七)返回值

    一.自定义创建模块 在base目录下创建_modules目录,你自己编写的模块都可以存放在该目录下,当前目录结构下: 1 2 3 4 5 6 7 8 [root@localhost:]# tree - ...

  10. 关于 startup_stm32f10x_hd.s 这个文件的一些说明

    关于 startup_stm32f10x_hd.s 这个文件的一些说明 startup_stm32f10x_hd.s 是一个启动文件,里面是使用汇编语言写好的基本程序,当STM32 芯片上电启动的时候 ...