前言:
对于ListView而言,自定义的Adapter对于显示复杂的界面有很大的灵活性 。使用自定义的Adapter需要继承BaseAdapter,然后重写getCount(),getView(),getItem,getItemId()4个方法。adapter在绘制listview时是先根据getCount()获得底层数据的个数来判断绘制item的个数,然后通过getView绘制单个item。
ListView实现的效果如下:
详细步骤:
1.新建Activity,在对应的布局文件中放置listview,textview和图片按钮;
2.新建一个布局文件,布局文件中包含图片,两个textview,一个checkbox
3.自定义MyAdapter继承BaseAdapter重写4个方法;
4.给listview绑定适配器,给按钮添加点击事件。
具体实现:
布局文件:(item.xml)
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" > 4 5 <ImageView 6 android:id="@+id/img" 7 android:layout_width="wrap_content" 8 android:layout_height="wrap_content" 9 android:layout_alignParentLeft="true" 10 android:layout_alignParentTop="true" /> 11 12 <TextView 13 android:id="@+id/title" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" 16 android:layout_alignParentTop="true" 17 android:layout_toRightOf="@+id/img" 18 android:textSize="20sp" 19 android:text="" /> 20 21 <TextView 22 android:id="@+id/info" 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:layout_alignBottom="@+id/img" 26 android:layout_toRightOf="@+id/img" 27 android:textSize="12sp" 28 android:text="" /> 29 <!--注意checkBox中focusable="false",如果不设置的话,listview的item点击事件没有用,因为item此时不能获取焦点--> 30 <CheckBox 31 android:id="@+id/cb" 32 android:layout_width="wrap_content" 33 android:layout_height="wrap_content" 34 android:layout_alignParentRight="true" 35 android:layout_alignParentTop="true" 36 android:focusable="false" 37 38 android:text="" /> 39 40 </RelativeLayout>
layout_main.xml
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <TextView 12 android:id="@+id/title" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_alignParentTop="true" 16 android:layout_centerHorizontal="true" 17 android:layout_toLeftOf="@id/title" 18 android:text="@string/title" /> 19 20 <ListView 21 android:id="@+id/listView1" 22 android:layout_width="match_parent" 23 android:layout_height="wrap_content" 24 android:layout_alignParentLeft="true" 25 android:layout_below="@+id/imageButton1" > 26 </ListView> 27 28 <ImageButton 29 android:id="@+id/imageButton1" 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content" 32 android:layout_alignParentTop="true" 33 android:layout_alignRight="@+id/listView1" 34 android:visibility="invisible" 35 android:src="@drawable/delete" /> 36 37 </RelativeLayout>
java代码:
1 public class MainActivity extends Activity { 2 ListView listview; 3 //list中存储listview的每一行的内容,每一行的内容存储在map中,根据键可以取出对应的值 4 List<Map<String,Object>> list; 5 ImageButton imgbtn; 6 //positions中保存的是当前选中的所有元素 7 List<Map<String,Object>> positions=new ArrayList<Map<String,Object>>(); 8 MyAdapter adapter=null; 9 @Override 10 protected void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.activity_main); 13 listview=(ListView) findViewById(R.id.listView1); 14 imgbtn=(ImageButton) findViewById(R.id.imageButton1); 15 list=getData(); 16 adapter =new MyAdapter(this,list); 17 listview.setAdapter(adapter); 18 listview.setOnItemClickListener(cl); 19 /* 20 * 根据选中的内容,删除listview中的显示 21 * positions中存放的是当前所有的选中项,每次删除完毕之后,应该把它清空,不然下次删除的时候 22 * 它还有数据,此时会出现问题。 23 * 删除完毕之后调用adapteradapter.notifyDataSetChanged(); 刷新view 24 */ 25 26 imgbtn.setOnClickListener(new OnClickListener() { 27 @Override 28 public void onClick(View v) { 29 Toast.makeText(getApplicationContext(), "delete", Toast.LENGTH_SHORT).show(); 30 //list.remove(int location)不能在for循环中使用 31 for(int i=0;i<positions.size();i++){ 32 list.remove(positions.get(i)); 33 } 34 //每一次删除完之后,把当前positions的元素删除 35 Iterator<Map<String,Object>> iterator=positions.iterator(); 36 while(iterator.hasNext()){ 37 iterator.next(); 38 iterator.remove(); 39 } 40 adapter.notifyDataSetChanged(); 41 //删除之后设置按钮不显示 42 imgbtn.setVisibility(View.INVISIBLE); 43 } 44 }); 45 46 } 47 48 //点击时确定当前选中的checkBox 49 50 @Override 51 public boolean onCreateOptionsMenu(Menu menu) { 52 // Inflate the menu; this adds items to the action bar if it is present. 53 getMenuInflater().inflate(R.menu.main, menu); 54 return true; 55 } 56 /* 57 * 设置item的点击事件 58 */ 59 OnItemClickListener cl=new OnItemClickListener() { 60 @Override 61 public void onItemClick(AdapterView<?> parent, View view, int position, 62 long id) { 63 // TODO Auto-generated method stub 64 Toast.makeText(getApplicationContext(), (String)list.get(position).get("title"), Toast.LENGTH_SHORT).show(); 65 } 66 }; 67 68 /* 69 * 提供音乐列表中的数据,包括每行数据中的歌手图片,歌曲名称,歌曲简介 70 */ 71 public List<Map<String,Object>> getData(){ 72 List<Map<String,Object>> list=new ArrayList<Map<String,Object>>(); 73 Map<String,Object> map=new HashMap<String,Object>(); 74 map.put("title", "真的爱你"); 75 map.put("info", "无法可修饰的一对手,带出温暖永远在背后"); 76 map.put("img", R.drawable.huangjiaju); 77 list.add(map); 78 79 map=new HashMap<String,Object>(); 80 map.put("title", "一生有你"); 81 map.put("info", "多少人曾爱慕你年轻时的容颜"); 82 map.put("img", R.drawable.shuimunianhua); 83 list.add(map); 84 85 map=new HashMap<String,Object>(); 86 map.put("title", "Moves Like Jagger"); 87 map.put("info", "Just you shoot for the stars,If it feels right"); 88 map.put("img", R.drawable.maroon5); 89 list.add(map); 90 91 return list; 92 } 93 94 95 96 //创建一个ViewHolder类,每个类对象包含ListView的Item的所有控件元素 97 private final class ViewHolder{ 98 public ImageView img; 99 public TextView title; 100 public TextView info; 101 public CheckBox cb; 102 } 103 //自定义adapter继承自BaseAdapter,实现两个方法 104 /* 105 * 106 */ 107 class MyAdapter extends BaseAdapter{ 108 private LayoutInflater inflater; 109 private List<Map<String,Object>> list; 110 111 /* 112 * 三种方式获取XML布局文件 113 * 1.LayoutInflater inflater=LayoutInflater.from(context); 114 * 2.LayoutInflater inflater=getLayoutInflater(); 115 * 3.LayoutInflater inflater=(LayoutInflater) context.getSystemService(LAYOUT_INFLATER_SERVICE); 116 */ 117 public MyAdapter(Context context,List<Map<String,Object>> list){ 118 inflater=LayoutInflater.from(context); 119 this.list=list; 120 } 121 @Override 122 public int getCount() { 123 // TODO Auto-generated method stub 124 return list.size(); 125 } 126 /* 127 * (non-Javadoc) 128 * holder里面放置每个item的所有控件 129 * 当convertview为空时,说明之前没有创建过这个Item,实例化一个新的view,通过setTag方法把holder放在convertView中 130 * 当convertview不为空时,此时可以直接从convertView取出,使用getTag 131 * @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup) 132 */ 133 @Override 134 public View getView(int position, View convertView, ViewGroup parent) { 135 // TODO Auto-generated method stub 136 ViewHolder holder=null; 137 if(convertView==null){ 138 holder=new ViewHolder(); 139 convertView=inflater.inflate(R.layout.item, null); 140 holder.img=(ImageView) convertView.findViewById(R.id.img); 141 holder.title=(TextView) convertView.findViewById(R.id.title); 142 holder.info=(TextView) convertView.findViewById(R.id.info); 143 holder.cb=(CheckBox) convertView.findViewById(R.id.cb); 144 convertView.setTag(holder); 145 }else{ 146 holder=(ViewHolder) convertView.getTag(); 147 } 148 holder.img.setBackgroundResource((Integer) list.get(position).get("img")); 149 holder.title.setText((CharSequence) list.get(position).get("title")); 150 holder.info.setText((CharSequence) list.get(position).get("info")); 151 holder.cb.setOnCheckedChangeListener(new checkedChangeListener(position)); 152 holder.cb.setChecked(false);//特别说明:把它全部设为false,是因为每次删除完之后会出现下一个界面上显示为选中但是不能删除,只有先取消再点击才有效,这应该是界面的绘制问题(猜测) 153 return convertView; 154 } 155 /* 156 * MyAdapter中的内部类实现了OnCheckedChangeListener接口, 157 * 提供一个构造函数,此处的构造函数的作用是传递了一个position参数, 158 * 可以与getView中的position关联起来,也可以在类内部的onCheckedChanged方法中使用。 159 * onCheckedChanged方法是在checkBox的状态改变时被调用的,为了删除按钮的点击事件中 160 * 能够获取到当前选中的所有项,所以每当选中一项,就把当前项放在一个list列表中,这样 161 * 在删除按钮处理点击事件时,就可以轻松完成。 162 * 一个小小的效果:有选中项时删除按钮显示,否则按钮消失。 163 * 实现:按钮初始状态为不可见,每当选中一项则设为可见,每当取消一项,判断是否还有选中, 164 * 若没有选中项,设为不可见 165 */ 166 class checkedChangeListener implements OnCheckedChangeListener{ 167 int position; 168 public checkedChangeListener(int position){ 169 this.position=position; 170 } 171 172 @Override 173 public void onCheckedChanged(CompoundButton buttonView, 174 boolean isChecked) { 175 /* 176 * 当某一个checkbox被选中时,先显示点击了当前item,然后把当前元素作为对象加入positions列表当中 177 * 设置删除按钮为可见 178 */ 179 if(isChecked){ 180 imgbtn.setVisibility(View.VISIBLE); 181 Toast.makeText(getApplicationContext(), "点击了"+(String)list.get(position).get("title"),Toast.LENGTH_SHORT).show(); 182 positions.add(list.get(position)); 183 }else{ 184 /* 185 * 当该项被取消时,先显示取消了此项,然后把当前项从列表中删除, 186 * 每次删除完之后,判断是否还有选中项,如果没有选中项,设置删除按钮不可见 187 */ 188 189 Toast.makeText(getApplicationContext(), "取消了"+(String)list.get(position).get("title"),Toast.LENGTH_SHORT).show(); 190 positions.remove(list.get(position)); 191 //判断当前是否有选中项,若没有,隐藏删除按钮 192 if(positions.size()==0){ 193 imgbtn.setVisibility(View.INVISIBLE); 194 } 195 } 196 } 197 } 198 199 /* 200 * 此处没有用到下面两个方法,故不作说明 201 * (non-Javadoc) 202 * @see android.widget.Adapter#getItem(int) 203 */ 204 @Override 205 public Object getItem(int position) { 206 // TODO Auto-generated method stub 207 return null; 208 } 209 210 @Override 211 public long getItemId(int position) { 212 // TODO Auto-generated method stub 213 return 0; 214 } 215 216 } 217 }
代码均已测试,无明显bug。因本人水平有限,出错之处在所难免,欢迎指正。