引言
———–最近由於項目需求,需要把兩種數據揉在一起然後通過兩種數據共有的時間來排序,裝在listView裏面。以前我們看到的多數都是listView裏面裝一種item所持的數據,或者更甚一點就是加了分割線什麼的。
現在我們一起來學習一下怎麼把多種數據用不同的item排序後裝在同一個listView裏面。
先上個圖
開始
首先我們先寫兩種不同的數據
—————– A類
public class A {
private String title;
private int time;
private String describe;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
}
—————– B類
public class B {
private int imgResourceID;
private int time;
private String content;
public int getImgResourceID() {
return imgResourceID;
}
public void setImgResourceID(int imgResourceID) {
this.imgResourceID = imgResourceID;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
A類和B類的數據除了time都是共有的,其他基本都是不一樣的,這就是我所謂的兩種不同的數據。
我們再來簡單地寫一下他們的item layout
———-item A 的layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
android:textSize="25sp"
android:id="@+id/item_list_for_a_title"
android:layout_gravity="center_horizontal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="time"
android:textSize="20sp"
android:layout_marginRight="50dp"
android:id="@+id/item_list_for_a_time"
android:layout_gravity="right" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="describe"
android:id="@+id/item_list_for_a_dec"
android:layout_gravity="center_horizontal" />
</LinearLayout>
———-item B 的layout
<?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">
<ImageView
android:id="@+id/item_list_for_b_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/item_list_for_b_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginight="50dp"
android:text="time"
android:textSize="20sp" />
<TextView
android:id="@+id/item_list_for_b_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="content"
android:textAppearance="? android:attr/textAppearanceMedium" />
</LinearLayout>
然後我們再來看看最重要的ABAdapter
先整體看一下,然後我們再來分解
package com.itspeed.naidou.app.adapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.itspeed.naidou.R;
import com.itspeed.naidou.model.bean.A;
import com.itspeed.naidou.model.bean.B;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Created by jafir on 15/9/14.
*/
public class ABAdapter extends BaseAdapter {
//itemA類的type標誌
private static final int TYPE_A = 0;
//itemB類的type標誌
private static final int TYPE_B = 1;
private Context context;
//整合數據
private List<Object> data = new ArrayList<>();
public ABAdapter(Context context, ArrayList<Object> as, ArrayList<Object> bs) {
this.context = context;
//把數據裝載同一個list裏面
//這裏把所有數據都轉爲object類型是爲了裝載同一個list裏面好進行排序
data.addAll(as);
data.addAll(bs);
//按時間排序來填充數據
Collections.sort(data, new MyComparator());
}
/**
* 獲得itemView的type
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
int result = 0;
if (data.get(position) instanceof A) {
result = TYPE_A;
} else if (data.get(position) instanceof B) {
result = TYPE_B;
}
return result;
}
/**
* 獲得有多少中view type
* @return
*/
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//創建兩種不同種類的viewHolder變量
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
//根據position獲得View的type
int type = getItemViewType(position);
if (convertView == null) {
//實例化
holder1 = new ViewHolder1();
holder2 = new ViewHolder2();
//根據不同的type 來inflate不同的item layout
//然後設置不同的tag
//這裏的tag設置是用的資源ID作爲Key
switch (type) {
case TYPE_A:
convertView = View.inflate(context, R.layout.item_list_for_a, null);
holder1.title = (TextView) convertView.findViewById(R.id.item_list_for_a_title);
holder1.time = (TextView) convertView.findViewById(R.id.item_list_for_a_time);
holder1.describe = (TextView) convertView.findViewById(R.id.item_list_for_a_dec);
convertView.setTag(R.id.tag_first, holder1);
break;
case TYPE_B:
convertView = View.inflate(context, R.layout.item_list_for_b, null);
holder2.content = (TextView) convertView.findViewById(R.id.item_list_for_b_content);
holder2.time = (TextView) convertView.findViewById(R.id.item_list_for_b_time);
holder2.img = (ImageView) convertView.findViewById(R.id.item_list_for_b_img);
convertView.setTag(R.id.tag_second, holder2);
break;
}
} else {
//根據不同的type來獲得tag
switch (type) {
case TYPE_A:
holder1 = (ViewHolder1) convertView.getTag(R.id.tag_first);
break;
case TYPE_B:
holder2 = (ViewHolder2) convertView.getTag(R.id.tag_second);
break;
}
}
Object o = data.get(position);
//根據不同的type設置數據
switch (type) {
case TYPE_A:
A a = (A) o;
holder1.describe.setText("ADescribe:" + a.getDescribe());
holder1.time.setText("ATime:" + a.getTime());
holder1.title.setText("ATitle" + a.getTitle());
break;
case TYPE_B:
B b = (B) o;
holder2.content.setText("BContent:" + b.getContent());
holder2.time.setText("BTime:" + b.getTime());
holder2.img.setImageResource(b.getImgResourceID());
break;
}
return convertView;
}
public class MyComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
//根據不同的情況來進行排序
if (arg0 instanceof A && arg1 instanceof B) {
A a = (A) arg0;
B b = (B) arg1;
return Integer.valueOf(a.getTime()).compareTo(b.getTime());
} else if (arg0 instanceof B && arg1 instanceof A) {
B b = (B) arg0;
A a = (A) arg1;
return Integer.valueOf(b.getTime()).compareTo(Integer.valueOf(a.getTime()));
} else if (arg0 instanceof A && arg1 instanceof A) {
A a0 = (A) arg0;
A a1 = (A) arg1;
return Integer.valueOf(a0.getTime()).compareTo(Integer.valueOf(a1.getTime()));
} else {
B b0 = (B) arg0;
B b1 = (B) arg1;
return Integer.valueOf(b0.getTime()).compareTo(Integer.valueOf(b1.getTime()));
}
}
}
/**
* item A 的Viewholder
*/
private static class ViewHolder1 {
TextView time;
TextView describe;
TextView title;
}
/**
* item B 的Viewholder
*/
private static class ViewHolder2 {
TextView time;
TextView content;
ImageView img;
}
}
首先是構造方法
public ABAdapter(Context context, ArrayList<Object> as, ArrayList<Object> bs) {
this.context = context;
//把數據裝載同一個list裏面
//這裏把所有數據都轉爲object類型是爲了裝載同一個list裏面好進行排序
data.addAll(as);
data.addAll(bs);
//按時間排序來填充數據
Collections.sort(data, new MyComparator());
}
我們把傳進來的倆種數據,進行整合,然後進行排序。
看看排序
public class MyComparator implements Comparator {
public int compare(Object arg0, Object arg1) {
//根據不同的情況來進行排序
if (arg0 instanceof A && arg1 instanceof B) {
A a = (A) arg0;
B b = (B) arg1;
return Integer.valueOf(a.getTime()).compareTo(b.getTime());
} else if (arg0 instanceof B && arg1 instanceof A) {
B b = (B) arg0;
A a = (A) arg1;
return Integer.valueOf(b.getTime()).compareTo(Integer.valueOf(a.getTime()));
} else if (arg0 instanceof A && arg1 instanceof A) {
A a0 = (A) arg0;
A a1 = (A) arg1;
return Integer.valueOf(a0.getTime()).compareTo(Integer.valueOf(a1.getTime()));
} else {
B b0 = (B) arg0;
B b1 = (B) arg1;
return Integer.valueOf(b0.getTime()).compareTo(Integer.valueOf(b1.getTime()));
}
}
}
是按照時間順序來排列的,重寫了Comparator的compare方法
看看那兩個最重要的方法
getItemViewType
如果通過數據來判斷是哪種type
/**
* 獲得itemView的type
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
int result = 0;
if (data.get(position) instanceof A) {
result = TYPE_A;
} else if (data.get(position) instanceof B) {
result = TYPE_B;
}
return result;
}
getViewTypeCount
/**
* 獲得有多少中view type
* @return
*/
@Override
public int getViewTypeCount() {
return 2;
}
attention!
這裏有個很容易犯的錯,我就犯了,花了我很久的時間才排查出來。
//itemA類的type標誌
private static final int TYPE_A = 0;
//itemB類的type標誌
private static final int TYPE_B = 1;
就是在寫type的時候 這裏的int類型的標誌一定要從0 開始
我之前就是從1 開始,然後就會報一個超出數組的錯誤
09-14 22:13:04.039 3158-3158/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.itspeed.naidou, PID: 3158
java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
at android.widget.AbsListView$RecycleBin.addScrapView(AbsListView.java:6739)
at android.widget.AbsListView.trackMotionScroll(AbsListView.java:5091)
at android.widget.AbsListView.onGenericMotionEvent(AbsListView.java:3811)
at android.view.View.dispatchGenericMotionEventInternal(View.java:7801)
at android.view.View.dispatchGenericMotionEvent(View.java:7782)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:1824)
at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:1777)
at android.view.View.dispatchGenericMotionEvent(View.java:7775)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchGenericMotionEvent(PhoneWindow.java:2076)
at com.android.internal.policy.impl.PhoneWindow.superDispatchGenericMotionEvent(PhoneWindow.java:1525)
at android.app.Activity.dispatchGenericMotionEvent(Activity.java:2494)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchGenericMotionEvent(PhoneWindow.java:2030)
at android.view.View.dispatchPointerEvent(View.java:7888)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3947)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3826)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3392)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3442)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3411)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3518)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3419)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3575)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3392)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3442)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3411)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3419)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3392)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5532)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5512)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5483)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5612)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:138)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.int
所以一定要注意了。
接下來就是我們最重要的部分getView
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//創建兩種不同種類的viewHolder變量
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
//根據position獲得View的type
int type = getItemViewType(position);
if (convertView == null) {
//實例化
holder1 = new ViewHolder1();
holder2 = new ViewHolder2();
//根據不同的type 來inflate不同的item layout
//然後設置不同的tag
//這裏的tag設置是用的資源ID作爲Key
switch (type) {
case TYPE_A:
convertView = View.inflate(context, R.layout.item_list_for_a, null);
holder1.title = (TextView) convertView.findViewById(R.id.item_list_for_a_title);
holder1.time = (TextView) convertView.findViewById(R.id.item_list_for_a_time);
holder1.describe = (TextView) convertView.findViewById(R.id.item_list_for_a_dec);
convertView.setTag(R.id.tag_first, holder1);
break;
case TYPE_B:
convertView = View.inflate(context, R.layout.item_list_for_b, null);
holder2.content = (TextView) convertView.findViewById(R.id.item_list_for_b_content);
holder2.time = (TextView) convertView.findViewById(R.id.item_list_for_b_time);
holder2.img = (ImageView) convertView.findViewById(R.id.item_list_for_b_img);
convertView.setTag(R.id.tag_second, holder2);
break;
}
} else {
//根據不同的type來獲得tag
switch (type) {
case TYPE_A:
holder1 = (ViewHolder1) convertView.getTag(R.id.tag_first);
break;
case TYPE_B:
holder2 = (ViewHolder2) convertView.getTag(R.id.tag_second);
break;
}
}
Object o = data.get(position);
//根據不同的type設置數據
switch (type) {
case TYPE_A:
A a = (A) o;
holder1.describe.setText("ADescribe:" + a.getDescribe());
holder1.time.setText("ATime:" + a.getTime());
holder1.title.setText("ATitle" + a.getTitle());
break;
case TYPE_B:
B b = (B) o;
holder2.content.setText("BContent:" + b.getContent());
holder2.time.setText("BTime:" + b.getTime());
holder2.img.setImageResource(b.getImgResourceID());
break;
}
return convertView;
}
我們創建了兩種viewholder 來裝不同item layout裏面的view
/**
* item A 的Viewholder
*/
private static class ViewHolder1 {
TextView time;
TextView describe;
TextView title;
}
/**
* item B 的Viewholder
*/
private static class ViewHolder2 {
TextView time;
TextView content;
ImageView img;
}
跟往常的 setTag 和 getTag一樣,只是這裏需要判斷一個type ,通過getItemViewType 來對不同的item inflate不同的layout
這裏還要說一下
這裏的setTag方法 有兩個參數 第一個是key,
它不是String 而是 int ,是一個資源ID的key,之前我就隨便定了一個1 或者2,然而那樣並不行,因爲ID可能衝突或者產生其他錯誤
所以我用了一個方法
在String 裏面 寫了2個item ,讓系統自己分配資源ID ,就完美解決了
<resources>
<string name="app_name">Naidou</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<!-- topic-->
<!-- title-->
<!-- tab-->
<string name="tab_chide">喫的</string>
<string name="tab_liaode">聊的</string>
<string name="tab_guangde">逛的</string>
<string name="tab_wode">我的</string>
<item name="tag_first" type="id"></item>
<item name="tag_second" type="id"></item>
</resources>
然後是通過type來設置不同的數據
Object o = data.get(position);
//根據不同的type設置數據
switch (type) {
case TYPE_A:
A a = (A) o;
holder1.describe.setText("ADescribe:" + a.getDescribe());
holder1.time.setText("ATime:" + a.getTime());
holder1.title.setText("ATitle" + a.getTitle());
break;
case TYPE_B:
B b = (B) o;
holder2.content.setText("BContent:" + b.getContent());
holder2.time.setText("BTime:" + b.getTime());
holder2.img.setImageResource(b.getImgResourceID());
break;
}
這樣一來我們的內容就講完了。
多的話不需要說,大家一看代碼便知
剩下最後一點就是設置一下假數據吧,然後測試一下效果
private ABAdapter abAdapter;
private ArrayList<Object> as = new ArrayList<>();
private ArrayList<Object> bs = new ArrayList<>();
這裏的倆個arrayList 數組 都是Object類型的,目的就是爲了後面的數據整合,因爲要把兩種數據裝在同一個數組裏面進行排序,所以這樣做。
但是其實數據的原來類型A或者B,還是可以通過instance of 來辨別的。
private void setDate() {
//這裏的time是從100開始+2*i
for(int i = 0;i < 10;i++){
CookBook cookBook = new CookBook();
cookBook.setPortraitUrl("wwww");
cookBook.setTime(""+(100+2*i));
cookBooks.add(cookBook);
}
//這裏是從95 開始+3*i,
//目的是爲了 讓他們的時間有交叉,然後才能更好的體現排序
for(int i = 0;i < 10;i++){
Topic topic = new Topic();
topic.setTitle("topic");
topic.setTime(""+(95+3*i));
topics.add(topic);
}
}
setData();
abAdapter = new ABAdapter(aty,as,bs);
listView.setAdapter(abAdapter);
好啦,大功告成!!!!!
最後
希望這個東西有能幫助到你們,多謝大家的支持!
如果有問題,請不吝多提,我們一起交流學習。