引言
———–最近由于项目需求,需要把两种数据揉在一起然后通过两种数据共有的时间来排序,装在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);
好啦,大功告成!!!!!
最后
希望这个东西有能帮助到你们,多谢大家的支持!
如果有问题,请不吝多提,我们一起交流学习。