ListView布局之View复用原理举例

来源:互联网 发布:传统产业优化升级 编辑:程序博客网 时间:2024/05/17 04:43

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 */@EBeanpublic class Model {private int imgHead;//头像资源IDprivate 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类,重写它的几个重要方法:

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

按照我们的需求,我们必须在getView类中,为Item布局中的每一个View进行关联,设置相应的参数,而对于Button,还要设置相应的事件监听器。我们必须注意的是:在设置事件监听器的时候,我们必须将当前的Item的位置信息position传递给监听器,否则的话,onClick方法无法知道当前按下的是哪个按钮。因此,我们写了一个内部类,实现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>();}@Overridepublic 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;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn listViewData.get(position);}@Overridepublic int getCount() {// TODO Auto-generated method stubif(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;}@Overridepublic 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{@ViewByIdListView listView;//ListView的设配器private BaseAdapter1 baseAdapter1;@AfterViewsvoid 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();}@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {// TODO Auto-generated method stubLog.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>();}/** * 根据发送消息的类型进行分类,不同的消息类型不同的布局 */@Overridepublic 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;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn position;}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn listViewData.get(position);}@Overridepublic int getCount() {// TODO Auto-generated method stubif(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;}@Overridepublic 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{@ViewByIdListView listView;private ChatBaseAdapter chatBaseAdapter;@AfterViewsvoid 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();}@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {// TODO Auto-generated method stubLog.d("ItemClick", "pos="+position);String string = "clicked item"+position+"content="+chatBaseAdapter.getMsg(position).getContent();Toast.makeText(this, string, Toast.LENGTH_SHORT).show();}}

效果:



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

原理基本一样。

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



2 0
原创粉丝点击