Introduction to this section:
This section is the last one in the ListView subsection, bringing you the implementation of ListView multi-layout Items. What is ListView Item multi-layout? Take a chat list like QQ as an example:
If it were built with a single ListView, then wouldn't there be two different kinds of Items on one ListView! One on the left, one on the right. Hehe, this section will teach you how to implement ListView multi-layout!
1. Key points explanation:
Override the getItemViewType() method to specify which category a View belongs to, and the getViewTypeCount() method to return the total number of categories! Then in getView, call getItemViewType to get the corresponding category, and load the corresponding View!
2. Code implementation:
Here, we directly use the two layouts from the previous section, and then write a separate Adapter that overrides the places mentioned in the key points:
MutiLayoutAdapter.java:
/**
* Created by Jay on 2015/9/23 0023.
*/
public class MutiLayoutAdapter extends BaseAdapter{
//定义两个类别标志
private static final int TYPE_BOOK = 0;
private static final int TYPE_APP = 1;
private Context mContext;
private ArrayList<Object> mData = null;
public MutiLayoutAdapter(Context mContext,ArrayList<Object> mData) {
this.mContext = mContext;
this.mData = mData;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
//多布局的核心,通过这个判断类别
@Override
public int getItemViewType(int position) {
if (mData.get(position) instanceof App) {
return TYPE_APP;
} else if (mData.get(position) instanceof Book) {
return TYPE_BOOK;
} else {
return super.getItemViewType(position);
}
}
//类别数目
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
int type = getItemViewType(position);
ViewHolder1 holder1 = null;
ViewHolder2 holder2 = null;
if(convertView == null){
switch (type){
case TYPE_APP:
holder1 = new ViewHolder1();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_one, parent, false);
holder1.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
holder1.txt_aname = (TextView) convertView.findViewById(R.id.txt_aname);
convertView.setTag(R.id.Tag_APP,holder1);
break;
case TYPE_BOOK:
holder2 = new ViewHolder2();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_two, parent, false);
holder2.txt_bname = (TextView) convertView.findViewById(R.id.txt_bname);
holder2.txt_bauthor = (TextView) convertView.findViewById(R.id.txt_bauthor);
convertView.setTag(R.id.Tag_Book,holder2);
break;
}
}else{
switch (type){
case TYPE_APP:
holder1 = (ViewHolder1) convertView.getTag(R.id.Tag_APP);
break;
case TYPE_BOOK:
holder2 = (ViewHolder2) convertView.getTag(R.id.Tag_Book);
break;
}
}
Object obj = mData.get(position);
//设置下控件的值
switch (type){
case TYPE_APP:
App app = (App) obj;
if(app != null){
holder1.img_icon.setImageResource(app.getaIcon());
holder1.txt_aname.setText(app.getaName());
}
break;
case TYPE_BOOK:
Book book = (Book) obj;
if(book != null){
holder2.txt_bname.setText(book.getbName());
holder2.txt_bauthor.setText(book.getbAuthor());
}
break;
}
return convertView;
}
//两个不同的ViewHolder
private static class ViewHolder1{
ImageView img_icon;
TextView txt_aname;
}
private static class ViewHolder2{
TextView txt_bname;
TextView txt_bauthor;
}
}
There's something to note here: convertView.setTag(R.id.Tag_APP, holder1); Usually we directly call setTag(Object). This is an overloaded method of setTag, taking a unique key and an object after it! Unique!!! At first I directly used TYPE_BOOK as the first parameter, and then I got the following error:
The key must be an application-specific resource idThe point is that the former must be unique. Defining a final int variable or hardcoding a value won't work. The approach here is to add it directly in strings.xml:
<item name="Tag_APP" type="id"></item> <item name="Tag_Book" type="id"></item>
Of course, you can also create a separate ids.xml file under res/values/ and paste the above code into it! Besides this, there is another thing to note: the flag for distinguishing categories must start from 0, otherwise you will get an error like the following:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private static final int TYPE_BOOK = 0;
private static final int TYPE_APP = 1;
private ListView list_content;
private ArrayList<Object> mData = null;
private MutiLayoutAdapter myAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//数据准备:
mData = new ArrayList<Object>();
for(int i = 0;i < 20;i++){
switch ((int)(Math.random() * 2)){
case TYPE_BOOK:
mData.add(new Book("《第一行代码》","郭霖"));
break;
case TYPE_APP:
mData.add(new App(R.mipmap.iv_icon_baidu,"百度"));
break;
}
}
list_content = (ListView) findViewById(R.id.list_content);
myAdapter = new MutiLayoutAdapter(MainActivity.this,mData);
list_content.setAdapter(myAdapter);
}
}
The above randomly generates 0 and 1. If it's 0, add a Book object to the collection; if it's 1, add an App object!
3. Code download:
ListViewDemo6.zip
Section summary:
Alright, this section explained the implementation of ListView Item multi-layout. It's just overriding two methods, then making a judgment in getView() to set different layouts~ The code is very simple~
Let's put ListView knowledge aside for now. Of course, ListView knowledge is not limited to this. Async loading, optimization, etc. — we will learn all of these in the advanced part~ That's all for now, thanks~


