ListView的不同item加载不同Layout

在重写ListView的BaseAdapter时,我们常常在getView()方法中复用convertView,优化ListView以提高性能。convertView在Item为单一的同种类型布局时,能够回收并重用,但是多个Item布局类型不同时,convertView的回收和重用会出现问题。比如有些行为纯文本,有些行则是图文混排,这里纯文本行为一类布局,图文混排的行为第二类布局。单一类型的ListView很简单,下面着重介绍一下ListView包含多种类型视图布局的情形,首先看图效果展示:

点击下载该内容源码

      

 

 

 

 

 

 

 

 

 

 

 

在编写代码之前呢,我们需要做这些工作并了解其作用:

  1)重写 getViewTypeCount() – 该方法返回多少个不同的布局

  2)重写 getItemViewType(int) – 根据position返回相应的Item

  3)根据view item的类型,在getView中创建正确的convertView

下面让我们看一下代码怎么实现:

MainActivity.class

 

/**
 * 
 *ListViewDifferentType
 * @author Yuanjunhua
 *
 * 2014-7-28下午6:23:39
 */
public class MainActivity extends Activity {

	private ListView listView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		listView=(ListView) findViewById(R.id.lsitview);
		String[] name1=new String[]{"北京","上海","南京","郑州","轻工业学院","姜寨村"};
		String[] name2=new String[]{"北京","上海","南京","郑州","轻工业学院","姜寨村"};
		Integer[] id2=new Integer[]{
				R.drawable.jx_left_listitem_1,
				R.drawable.jx_left_listitem_2,
				R.drawable.jx_left_listitem_3,
				R.drawable.jx_left_listitem_4,
				R.drawable.jx_left_listitem_5,
				R.drawable.jx_left_listitem_6};
		
		List<String> list1=new ArrayList<String>();
		fillListMethod(list1,name1);
		
		List<Map<String,Integer>> list2=new ArrayList<Map<String,Integer>>();
		fillMapMethod(list2,name2,id2);
		
		Log.d("mapList", "mapList=="+list1);
		Log.d("strList", "strList=="+list2);
		listView.setAdapter(new MyAdapter(this, list1, list2));
		
	}

	private void fillMapMethod(List<Map<String, Integer>> list,String[] name,Integer[] id) {
		// TODO Auto-generated method stub
		for (int i = 0; i < name.length; i++) {
			Map<String,Integer> map=new HashMap<String, Integer>();
			map.put(name[i], id[i]);
			list.add(map);
		}
	}

	private void fillListMethod(List<String> list,String[] name) {
		// TODO Auto-generated method stub
		for (int i = 0; i < name.length; i++) {
			list.add(name[i]);
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

 

继承BaseAdapter

 

/**
 * 
 *ListViewDifferentType
 * @author Yuanjunhua
 *
 * 2014-7-28下午6:23:31
 */
public class MyAdapter extends BaseAdapter {

	private LayoutInflater li;
	private List<String> list;
	private List<Map<String,Integer>> map;
	private final int TYPE_ONE=0,TYPE_TWO=1,TYPE_COUNT=2;
	public MyAdapter(Context context,List<String> list,List<Map<String,Integer>> map) {
		// TODO Auto-generated constructor stub
		this.list =list;
		this.map =map;
		li=LayoutInflater.from(context);
	}
	
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return list.size()+map.size();
	}
	
	/** 该方法返回多少个不同的布局*/
	@Override
	public int getViewTypeCount() {
		// TODO Auto-generated method stub
		return TYPE_COUNT;
	}
	/** 根据position返回相应的Item*/
	@Override
	public int getItemViewType(int position) {
		// TODO Auto-generated method stub
		int po = position % 2;
		if (po == TYPE_ONE)
			return TYPE_ONE;
		else
			return TYPE_TWO;
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return list.get(position%6);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position%6;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		ViewHolder1 vh1=null;
		ViewHolder2 vh2=null;
		int type=getItemViewType(position);
		if(convertView==null){
			switch (type) {
			case TYPE_ONE:
				vh1=new ViewHolder1();
				convertView=li.inflate(R.layout.item_one, null);
				vh1.tv1=(TextView) convertView.findViewById(R.id.tv1);
				
				convertView.setTag(vh1);
				
				break;
			case TYPE_TWO:
				vh2=new ViewHolder2();
				convertView=li.inflate(R.layout.item_two, null);
				vh2.tv2=(TextView) convertView.findViewById(R.id.tv2);
				vh2.img2=(ImageView) convertView.findViewById(R.id.img2);
				convertView.setTag(vh2);
				break;
			}
		}
		else{
			switch (type) {
			case TYPE_ONE:
				vh1=(ViewHolder1) convertView.getTag();
				break;
			case TYPE_TWO:
				vh2=(ViewHolder2) convertView.getTag();
				break;
			}
		}
		
		switch (type) {
		case TYPE_ONE:
			if(position<5)
			vh1.tv1.setText(list.get((position%6)-(position%6)/2));
			if(position>5)
				vh1.tv1.setText(list.get((position%6)-(position%6)/2+3));
			break;
		case TYPE_TWO:
			int i=0;
			String txt=null;
			Map<String,Integer> mapSI=null;
			if(position<6){
				i=(position%6)-(position%6+1)/2;
				mapSI=map.get(i);
				Iterator<String> it=mapSI.keySet().iterator();
				if(it.hasNext()) txt=it.next();
			}
				
			if(position>6){
				i=(position%6)-(position%6+1)/2+3;
				mapSI=map.get(i);
				Iterator<String> it=mapSI.keySet().iterator();
				if(it.hasNext()) txt=it.next();
			}
			vh2.tv2.setText(txt);
			vh2.img2.setBackgroundResource(mapSI.get(txt));
			Log.d("txt", "txt=="+txt);
			break;
		}
		return convertView;
	}
	
	static class ViewHolder1{
		TextView tv1;
	}
	static class ViewHolder2{
		TextView tv2;
		ImageView img2;
	}

}

实现上图的效果就用这么几句代码!!

 

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在ListView中添加不同的动态布局,你需要在适配器中重写getView()方法。在该方法中,你可以通过position参数来判断当前的数据项需要使用哪种布局。 以下是一个简单的示例代码,假设我们有两种数据类型:TypeA和TypeB,需要在ListView中显示: ```kotlin class MyAdapter(private val context: Context, private val data: List<Any>) : BaseAdapter() { private val TYPE_A = 0 private val TYPE_B = 1 override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { var view = convertView val type = getItemViewType(position) if (view == null) { // 根据不同类型加载不同布局 view = if (type == TYPE_A) { LayoutInflater.from(context).inflate(R.layout.layout_type_a, parent, false) } else { LayoutInflater.from(context).inflate(R.layout.layout_type_b, parent, false) } } // 根据不同类型填充数据 if (type == TYPE_A) { // 填充 Type A 的数据 val item = data[position] as TypeA // ... } else { // 填充 Type B 的数据 val item = data[position] as TypeB // ... } return view } override fun getItem(position: Int): Any { return data[position] } override fun getItemId(position: Int): Long { return position.toLong() } override fun getCount(): Int { return data.size } override fun getItemViewType(position: Int): Int { // 根据不同数据类型返回不同的类型值 return if (data[position] is TypeA) TYPE_A else TYPE_B } override fun getViewTypeCount(): Int { // 返回布局类型的数量,这里有两种类型 return 2 } } ``` 在上面的代码中,我们首先定义了两个常量TYPE_A和TYPE_B,用于表示不同布局类型。在getView()方法中,我们根据position参数和getItemViewType()方法的返回值来判断当前数据项需要使用哪种布局。如果convertView为空,则根据不同的类型加载不同布局。然后在各自的分支中填充数据即可。最后,我们还需要在适配器中重写getItemViewType()和getViewTypeCount()方法,用于返回布局类型和布局类型数量。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值