在写完基础的布局之后,下一课我们会学习一下如何使用Android中一个非常重要,但是对于新手略有困难的ListView,甚至很久以前都有人说过,会不会写ListView是Android能否入门的第一步。
好了,说了这么多,写这个教程也是希望大家能加深一下印象,提前预习,以免听沙龙的时候一头雾水。
如上图所示的界面就是一个ListView,如名字所说,ListView就是一个列表控件,通过名为Adapter的内容填充器,对其进行填充。
这是ListView的原理图,其中的Cursor大家不用管,Cursor涉及到了数据库的操作,主要看的一条线是从ArrayList-----》 Adapter -------》 ListView。
从这个步骤我们可以看出,使用ListView的过程,就是从数据(Arraylist),到接收器(Apapter)再放进ListView中的。
其中的ArrayList可以认为是可以放任意东西的一种链表使用ArrayList<对象>的方式进行存储。
这就是我们需要的一个样式,其中出现了一个图标,一段文本,一个可点击的框(CheckBox)。
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="wrap_content"> 6 <ImageView 7 android:id="@+id/list_img" 8 android:layout_margin="8dp" 9 android:src="@mipmap/ic_launcher" 10 android:layout_width="32dp" 11 android:layout_height="32dp" /> 12 <TextView 13 android:id="@+id/list_text" 14 android:singleLine="true" 15 android:text="哈哈哈哈哈哈哈哈" 16 android:layout_centerVertical="true" 17 android:layout_toRightOf="@+id/list_img" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content" /> 20 <CheckBox 21 android:layout_centerVertical="true" 22 android:layout_alignParentRight="true" 23 android:layout_gravity="right" 24 android:layout_width="wrap_content" 25 android:layout_height="wrap_content" /> 26 </RelativeLayout>
当然作为我们默认的一个布局样式,里面最好什么都不填充。
1 public class ListInfo { 2 private int list_img; 3 private String list_text; 4 private boolean list_click; 5 6 public ListInfo(int list_img, String list_text, boolean list_click) { 7 this.list_img = list_img; 8 this.list_text = list_text; 9 this.list_click = list_click; 10 } 11 12 public int getList_img() { 13 return list_img; 14 } 15 16 public String getList_text() { 17 return list_text; 18 } 19 20 public boolean isList_click() { 21 return list_click; 22 } 23 }
这个类中包含刚才视图中的三个信息,一个资源id,一个文本,一个是否点击的boolean值。
继承之后会默认复写四个方法。
1 @Override 2 public int getCount() { 3 return 0; 4 } 5 6 @Override 7 public Object getItem(int i) { 8 return null; 9 } 10 11 @Override 12 public long getItemId(int i) { 13 return 0; 14 } 15 16 @Override 17 public View getView(int i, View view, ViewGroup viewGroup) { 18 return null; 19 }
从名字中就能看出这些方法是用来干什么的了,getCount获得总数目,getItem返回每项的一个对象,getItemId直接返回i就好,getView获取每项的视图。
除了这些,我们还需要两个东西,一个Context上下文用于需找View,一个ArrayList就是我们用于填充的数据了,这两个东西都要通过构造函数来实现。
1 private ArrayList<ListInfo> userList; 2 private Context context;
ArrayList里面存放的对象就是我们刚才创建的那个ListInfo。
构造函数:
public ListAdapter(Context context, ArrayList<ListInfo> userList) { this.context = context; this.userList = userList; }
有了这些东西我们就能修改之前的三个方法了:
@Override public int getCount() { return userList.size(); } @Override public Object getItem(int i) { return userList.get(i); } @Override public long getItemId(int i) { return i; }
分别用数据的size,get的Item,还有i返回。
我们都知道布局与数据建立连接是通过先找到布局,再填充数据的方式进行的,但是ListView有很多子项,每次都要找一个个布局再填充是一个非常消耗系统机能的方式,
所以我们使用ViewHolder的方式进行缓存布局,防止多次轮询的消耗。
所谓的ViewHolder就是通过一个内部类来缓存布局:
private class ViewHolder{ private ImageView imageView; private TextView textView; private CheckBox checkBox; }
这个类里包含我们一个布局所需的全部控件,一个ImageView,一个TextView,一个CheckBox,这个类作为ListAdapter的一个内部类。
然后这是getview:
1 @Override 2 public View getView(int i, View view, ViewGroup viewGroup) { 3 // 首先新建viewHolder实例,由于getView这个函数会在每个Item生成的时候都运行一次, 4 // 所以我们用了这种写法 5 ViewHolder viewHolder = null; 6 // view还是null时,此时为第一次创建 7 if(view == null){ 8 // 新建实例 9 viewHolder = new ViewHolder(); 10 // 为View添加布局,此处View是Item的View 11 view = LayoutInflater.from(context).inflate(R.layout.list_item,null); 12 // 为ViewHolder填充 13 viewHolder.imageView = (ImageView)view.findViewById(R.id.list_img); 14 viewHolder.textView = (TextView)view.findViewById(R.id.list_text); 15 viewHolder.checkBox = (CheckBox)view.findViewById(R.id.list_check); 16 // 给View设定额外的标签,可存储一个数据,我们把ViewHolder存进去 17 view.setTag(viewHolder); 18 }else { 19 // 此处已经是>=2 创建Item了 20 // 把view从tag中拿出来 21 viewHolder = (ViewHolder)view.getTag(); 22 } 23 // 从ArrayList找到当前项的数据 24 ListInfo listInfo = userList.get(i); 25 // 逐个填充 26 viewHolder.imageView.setImageResource(listInfo.getList_img()); 27 viewHolder.textView.setText(listInfo.getList_text()); 28 viewHolder.checkBox.setChecked(listInfo.isList_click()); 29 return view; 30 }
注释写的已经很详细了。
布局中添加:
1 <ListView 2 android:id="@+id/listview" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 />
Activity中添加:
1 ListView listView = (ListView)findViewById(R.id.listview); 2 3 ArrayList<ListInfo> arrayList = new ArrayList<>(); 4 5 for(int i = 0;i < 10;i++){ 6 arrayList.add(new ListInfo(R.mipmap.ic_launcher,"蛤蛤蛤蛤",true)); 7 arrayList.add(new ListInfo(R.mipmap.ic_launcher,"蛤蛤",false)); 8 } 9 10 ListAdapter adapter = new ListAdapter(this,arrayList); 11 12 listView.setAdapter(adapter);
注意到新建了ArrayList然后随意new了20个子项。
然后填充进Adapter里,然后再给ListView添加Adapter就可以了。
这就是最后完成的界面了!大家试试吧!
源码下载