当前位置: 代码迷 >> Android >> Android应用之——利用getItemViewType为Listview的item设立不同的布局
  详细解决方案

Android应用之——利用getItemViewType为Listview的item设立不同的布局

热度:38   发布时间:2016-04-28 05:08:38.0
Android应用之——利用getItemViewType为Listview的item设置不同的布局

一、概述

在项目的需求中,有一处需要显示一个交易记录的列表,这个列表很容易让人联想到用listview来实现,但是这个列表又有稍许不同的地方,那就是它里面的item并不是一样的布局,其中某些部分显示的是消费的记录,而有些地方显示的是充值的记录,也就对应了不同的item布局。而且,这两处地方都是从服务端获取数据的,这两个item的数据对应的类内容也各不相同,该怎么处理呢?

下面来一步步实现这个效果。

二、先看效果图


三、实现步骤

实现的原理就是listview的adapter中的一个关键的方法就是getItemViewType(getItemViewType),这个方法有一个参数是position,有了这个position我们就可以对list集合中的不同位置的数据进行不同的处理,进而标识不同的type,将list中的数据进行分类处理。

首先进行,数据的准备:

在这个项目中,数据源是从服务端获取的json数据,数据的格式如下:

{    "status_code": "0",    "result": [        {            "mr_content": {                "point": "10",                "member_money": "100",                "pay_money": "300",                "cash": "200",                "bonus": "消费满200元立减50元餐券1张",                "activities": "三锅鸡1元任吃",                "coupon": "满100送50",                "branch_name": "四海一家"            },            "mr_id": "25",            "mr_createtime": "1333333333",            "mr_type": "0",            "user_id": "108",            "merchant_id": "1",            "branch_id": "1",            "branch_name": "ffff"        },        {            "mr_content": {                "member_money": "300",                "branch_name": "四海一家"            },            "mr_id": "30",            "mr_createtime": "1333333333",            "mr_type": "1",            "user_id": "108",            "merchant_id": "1",            "branch_id": "1",            "branch_name": "fff"        }    ],    "status_desc": "ok"}

可以看到其中mr_content这个字段,是一个自定义对象,但是两个mr_content的内容不同,这里是分别为mr_content的内容定义两个不同的类还是如何处理呢?

一开始,我是分别为两个mr_content定义不同的类,后来发现这样行不通,因为这样做的话定义外层类的时候mr_content就无法指定数据类型了。所以,最后采用某人的方法将mr_content定义为一个类,将两个不同的mr_content的字段都定义进去,解析的时候不会出现问题,没有数据会显示null

下面是我定义的mr_content字段的数据类型ComsumAndChargeRecordBean

public class ComsumAndChargeRecordBean {	private String branch_name;	private String pay_money;	private String coupon;//使用特权	private String activities;	private String member_money;	private String cash;	private String point;	private String bonus;//	private String prestore_money;//预存款		public String getBranch_name() {		return branch_name;	}	public void setBranch_name(String branch_name) {		this.branch_name = branch_name;	}	public String getPay_money() {		return pay_money;	}	public void setPay_money(String pay_money) {		this.pay_money = pay_money;	}	public String getCoupon() {		return coupon;	}	public void setCoupon(String coupon) {		this.coupon = coupon;	}	public String getActivities() {		return activities;	}	public void setActivities(String activities) {		this.activities = activities;	}	public String getMember_money() {		return member_money;	}	public void setMember_money(String member_money) {		this.member_money = member_money;	}	public String getCash() {		return cash;	}	public void setCash(String cash) {		this.cash = cash;	}	public String getPoint() {		return point;	}	public void setPoint(String point) {		this.point = point;	}	public String getBonus() {		return bonus;	}	public void setBonus(String bonus) {		this.bonus = bonus;	}}


数据准备好了,下面是传入listview中进行显示:

布局文件:

<?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="vertical" >    <include        android:id="@+id/traderecord_layout"        layout="@layout/topview_activity" />    <ListView        android:id="@+id/lv_my_traderecord"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </ListView></LinearLayout>

两个不同item的布局文件就省略了,相信大家都会,这个没什么难度

下面是主界面代码:

<pre class="java" name="code">	protected void onCreate(Bundle savedInstanceState) {		// TODO Auto-generated method stub		super.onCreate(savedInstanceState);		setContentView(R.layout.activity_trade_record);				mListView = (ListView) findViewById(R.id.lv_my_traderecord);		E_TempTradeRecordAdapter adapter = new E_TempTradeRecordAdapter(				E_TradeRecordActivity.this, myModel.tradeRecordList);		mListView.setAdapter(adapter);		adapter.notifyDataSetChanged();	}

下面是adapter适配器的一部分代码:

字段和构造函数:

private static final String TAG = "E_TradeRecordAdapter";	private static final int TYPE_COUNT = 2;//item类型的总数	private static final int TYPE_COMSUM = 0;//消费类型	private static final int TYPE_CHARGE = 1;//充值类型	private ArrayList<TradeRecordBean> dataList = new ArrayList<TradeRecordBean>();//数据集合	private Context mContext;	private int currentType;//当前item类型	public E_TempTradeRecordAdapter(Context mContext,			ArrayList<TradeRecordBean> dataList) {		super();		this.dataList = dataList;		this.mContext = mContext;	}

几个重要方法:

@Override	public int getCount() {		// TODO Auto-generated method stub		return dataList.size();	}	@Override	public Object getItem(int position) {		// TODO Auto-generated method stub		return dataList.get(position);	}	@Override	public long getItemId(int position) {		// TODO Auto-generated method stub		return position;	}

获取子item的类型 获取类型的数量  这里是根据字段Mr_type来确定的,json数据里面是根据这个字段来确定消费记录的类型的。总之,在为item设置不同的布局的时候肯定有一个标记用来区分不同的item,你可以用这个作为判断的标记,来设置不同的type。

@Override	public int getItemViewType(int position) {		// TODO Auto-generated method stub		if ("0".equals(dataList.get(position).getMr_type())) {			return TYPE_COMSUM;// 消费类型		} else if ("1".equals(dataList.get(position).getMr_type())) {			return TYPE_CHARGE;// 充值类型		} else {			return 100;		}	}	@Override	public int getViewTypeCount() {		return TYPE_COUNT;	}

viewholder:缓存这几个textview控件

/**	 * 消费记录	 * @author yl	 *	 */	class ComsumViewHolder {		TextView branchnameCom;		TextView comsumemoney;		TextView useprevillage;		TextView yuezhifu;		TextView cash;		TextView thisscore;		TextView extrareward;		TextView prestoremoney;	}		/**	 * 充值记录	 * @author yl	 *	 */	class ChargeViewHolder {		TextView branchnameCha;		TextView prestoremoney;		TextView extrasmoney;		TextView totalmoney;	}


最后是getview方法:其中有一个关键的方法

currentType = getItemViewType(position);

这个方法获取到当前position的类型,也就是在前面的getItemViewType方法设置的类型。

其中对convertView进行了复用和holder的使用,算是对listview的优化吧。

当currentType == TYPE_COMSUM,消费类型时,加载comsumView = LayoutInflater.from(mContext).inflate(  R.layout.traderecord_item_comsume, null);消费类型的布局文件。反之,加载充值类型的布局文件。这样就可以达到为不同的item设置不同的布局文件了。

	public View getView(int position, View convertView, ViewGroup parent) {		// TODO Auto-generated method stub		View comsumView = null;		View chargeView = null;		ComsumAndChargeRecordBean record = (ComsumAndChargeRecordBean) dataList				.get(position).getMr_content();		currentType = getItemViewType(position);		if (currentType == TYPE_COMSUM) {			ComsumViewHolder comsumHolder = null;			if (convertView == null) {				comsumHolder = new ComsumViewHolder();				comsumView = LayoutInflater.from(mContext).inflate(						R.layout.traderecord_item_comsume, null);				comsumHolder.branchnameCom = (TextView) comsumView						.findViewById(R.id.tv_branch_name);				comsumHolder.comsumemoney = (TextView) comsumView						.findViewById(R.id.tv_comsumemoney);				comsumHolder.useprevillage = (TextView) comsumView						.findViewById(R.id.tv_useprevillage);				comsumHolder.yuezhifu = (TextView) comsumView						.findViewById(R.id.tv_yuezhifu);				comsumHolder.cash = (TextView) comsumView						.findViewById(R.id.tv_cash);				comsumHolder.thisscore = (TextView) comsumView						.findViewById(R.id.tv_thisscore);				comsumHolder.extrareward = (TextView) comsumView						.findViewById(R.id.tv_extrareward);				comsumView.setTag(comsumHolder);				convertView = comsumView;			} else {				comsumHolder = (ComsumViewHolder) convertView.getTag();			}			comsumHolder.branchnameCom.setText(DateFormatUtil.formatDate(Long					.valueOf(dataList.get(position).getMr_createtime()))					+ "  "					+ record.getBranch_name());// 消费时间和分店			comsumHolder.comsumemoney.setText(record.getPay_money());// 消费金额			comsumHolder.useprevillage.setText(record.getCoupon());// 使用特权			comsumHolder.yuezhifu.setText(record.getMember_money());// 余额支付			comsumHolder.cash.setText(record.getCash());// 现金支付			comsumHolder.thisscore.setText(record.getPoint());// 本次积分			comsumHolder.extrareward.setText(record.getBonus());// 额外奖励		} else if (currentType == TYPE_CHARGE) {			ChargeViewHolder chargeHoler = null;			if (convertView == null) {				chargeHoler = new ChargeViewHolder();				chargeView = LayoutInflater.from(mContext).inflate(						R.layout.traderecord_item_chongzhi, null);				chargeHoler.branchnameCha = (TextView) chargeView						.findViewById(R.id.tv_branchname_charge);				chargeHoler.prestoremoney = (TextView) chargeView						.findViewById(R.id.tv_prestoremoney);				chargeHoler.extrasmoney = (TextView) chargeView						.findViewById(R.id.tv_extrasmoney);				chargeHoler.totalmoney = (TextView) chargeView						.findViewById(R.id.tv_totalmoney);				chargeView.setTag(chargeHoler);				convertView = chargeView;			} else {				chargeHoler = (ChargeViewHolder) convertView.getTag();			}			chargeHoler.branchnameCha.setText(DateFormatUtil.formatDate(Long					.valueOf(dataList.get(position).getMr_createtime()))					+ " "					+ record.getBranch_name());// 消费时间和分店			// chargeHoler.prestoremoney.setText(record.getPrestore_money() +			// "元");// 存款			chargeHoler.extrasmoney.setText(record.getMember_money() + "元");// 余额			chargeHoler.totalmoney.setText(record.getMember_money() + "元");// 合计		}		return convertView;	}

上面就是整个效果的实现过程


四、总结

其实为listview的item设置不同的布局文件,达到上面的效果,步骤如下;

1、为不同的item写不同的布局文件,设置统一的javabean类

2、继承BaseAdapter类,实现getItemViewType(int position)和getViewTypeCount() 方法,根据这两个方法,为item设置不同的标记,也就是不同的type

3、在getView方法中,利用getItemViewType(position)方法获取当前的type类型,然后根据不同的type类型,加载不同的item布局文件。

4、其他的一些listview的优化同一般的listview没有很大区别。




  相关解决方案