关键点
ListView、Spinner、Adapters
在展现多条数据的时候,我们用List负责数据的显示,用Adapter来管理基本的数据
实例一
在用户界面实现一系列的数据项
Android提供了很多pre_built layout.例如simple_list_item_1。
1)activity_main.xml界面如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
2)创建Adapter来管理需要显示的数据:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建ArrayAdapter来管理数据,使用simple_list_item_1作为子布局,一个数组做为需要使用的数据
ArrayAdapter<String> aAdpt = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
new String[]{"Froyo", "Gingerbread", "Honeycomb", "Ice cream Sandwich", "Jelly Bean", " KitKat"});
//最后将adapter添加到listview中
ListView lv = (ListView) findViewById(R.id.list);
lv.setAdapter(aAdpt);
3)运行结果如下所示:
实例二
上述的例子是实现ListView,例二是实现Spinner,实现下拉列表。这两个是实际应用中最广泛的。
1)布局文件中,ListView换成Spinner
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
2)在strings.xml中定义要显示的字符数组days
<string-array name="days">
<item>Monday</item>
<item>Tuesday</item>
<item>Wednesday</item>
</string-array>
3)在主类中添加adapter,并在adapter添加到spinner中
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner spinner=(Spinner)findViewById(R.id.spinner);
ArrayAdapter<CharSequence> aAdpt = ArrayAdapter.createFromResource(this, R.array.days,
android.R.layout.simple_spinner_item);
aAdpt.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(aAdpt);
}
4)运行结果如下所示:
实例三
ListView事件处理,当数据以ListView的方式呈现的时候,我们可能需要点击ListView中的每个item得到更详细的信息
本实例实现的是点击每条item,弹出提示框,该例是建立在实例一的基础上,为ListView添加监听器,并实现处理监听事件
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> aView, View view, int position, long id) {
// We handle item click event
TextView tv = (TextView) view;
String text = (String) tv.getText();
Toast.makeText(MainActivity.this, "You clicked on " + text, Toast.LENGTH_LONG).show();
}
});
运行结果,点击对应的项目,弹出对话框
实例四
定制Adapter和View Holder Pattern
当标准的Adapter不能满足我们需求的时候,就需要定制Adapter,在已有BaseAdapter或其他Adapter的基础上补充功能,以符合需要。
本例是实现一个ListView,每条子项目有两行信息
1)首先我们新建一个继承BaseAdapter的CustomAdapter类
我们需要重写getCount()、getItem(int arg0)、getItemId(int arg0)、getView()这四个方法
public class CustomAdapter extends BaseAdapter {
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
2)在实现这些方法之前,我们先定义我们得数据模型。我们假设,我们的类名为Item,它包含两个属性,name和desc,现在我们需要定义一个子layout来显示这些数据
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/descr"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
3)在我们的adapter中,我们需要构造方法来传递我们得数据。
然后我们实现除getView()之外的方法
private Context ctx;
List<Item> itemList;
public CustomAdapter(Context ctx, List<Item> itemList) {
this.ctx = ctx;
this.itemList = itemList;
}
@Override
public int getCount() {
return itemList==null?0:itemList.size();
}
@Override
public Object getItem(int position) {
return itemList==null?0:itemList.get(position);
}
@Override
public long getItemId(int position) {
return itemList==null?0:itemList.get(position).hashCode();
}
接下来是getView()方法,它是所有方法中实现起来最复杂的,同时他是定制adapter的核心功能。
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater lInf = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = lInf.inflate(R.layout.item_layout, null);
}
TextView nameView = (TextView) v.findViewById(R.id.name);
TextView descrView = (TextView) v.findViewById(R.id.desc);
nameView.setText(itemList.get(position).name);
descrView.setText(itemList.get(position).desc);
return v;
}
4)主类中使用CustomAdapter
List<Item> list=new ArrayList<Item>();
list.add(new Item("name1","desc1"));
list.add(new Item("name2","desc2"));
list.add(new Item("name3","desc3"));
list.add(new Item("name4","desc4"));
CustomAdapter adapter=new CustomAdapter(this,list);
//最后将adapter添加到listview中
ListView lv = (ListView) findViewById(R.id.list);
lv.setAdapter(adapter);
5)运行结果如下所示
在上例中,getView方法是一个很长耗时的操作,当用户滚动界面时它会影响整个ListView的性能。应用View Holder Pattern,可以减少调用getView方法
上面的讲法好像没什么作用,我们分析实例三中没有ViewHolder情况,看一下getView()方法
1)当它第一次加载时,convertView是null。我们需要inflate list item layout并通过findViewById来查找TextView
2)第二次加载时,convertView不为空,但是我们仍然需要findViewById查找TextView
3)第三次仍然要频繁findViewById查找TextView,当有很多item和view在ListView中时,性能就会下降,这时候就用到了ViewHolder
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
TextHolder th = null;
if (v == null) {
LayoutInflater lInf = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = lInf.inflate(R.layout.item_layout, null);
TextView nameView = (TextView) v.findViewById(R.id.name);
TextView descrView = (TextView) v.findViewById(R.id.desc);
th = new TextHolder();
th.nameView = nameView;
th.descView = descrView;
v.setTag(th);
}
else
th = (TextHolder) v.getTag();
th.nameView.setText(itemList.get(position).name);
th.descView.setText(itemList.get(position).desc);
return v;
}
static class TextHolder {
TextView nameView;
TextView descView;
}
加入ViewHolder使得在第一次调用getView方法的时候,将ViewHolder做为convertView的一个标志,或者是一个临时存储convertView的地方,载第二次访问的时候,通过getTag直接获得view不需要通过findViewById的方法。