一、概述
在項目的需求中,有一處需要顯示一個交易記錄的列表,這個列表很容易讓人聯想到用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沒有很大區別