一、最简单的ListView
在布局文件里面,只需要定义一个ListView对象
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/list_view"></ListView>
在mainAcitivity里面:
给出数据,创建合适的适配器。simple_expandable_list_item_1是Andriod系统自带的ListView,每一行的TextView只显示一行的内容。
private String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(MainActivity.this,
android.R.layout.simple_expandable_list_item_1, data);
ListView listView = (ListView)findViewById(R.id.list_view);
listView.setAdapter(arrayAdapter);
二、通过自定义控件实现的ListView
要实现这种效果,首先自定义每一行的布局
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/number_image"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/number_name"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"/>
仿照最基本的用法,即给出某一类型的数据,建立适当的适配器。
所以首先建立一个自定义的类Number,把要显示在TextView的内容和图片的ID作为两个成员变量。
public class Number {
public Number(String name, int id){
this.name = name;
this.id = id;
}
public String getName(){
return name;
}
public int getId(){
return id;
}
private String name;
private int id;
}
接下来要创建一个类——Number类型的适配器,继承于ArrayAdapter<>。
public class NumberAdapter extends ArrayAdapter<Number> {
private int id;
public NumberAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<Number> objects) {
super(context, resource, objects);
id = resource;
}
//重写getView方法,使每个子项被滚动到屏幕时都能被调用
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
//据索引获取集合中的一个对象
Number number = getItem(position);
//从Context中,获得一个布局填充器,并且使用这个填充器来把xml布局文件转为View对象
View view = LayoutInflater.from(getContext()).inflate(id, parent, false);
//初始化ImageView对象和TextView对象
ImageView numberImage = view.findViewById(R.id.number_image);
TextView numberName = view.findViewById(R.id.number_name);
//设置图片和文本内容
numberImage.setImageResource(number.getId());
numberName.setText(number.getName());
return view;
}
}
在mainActivity里面
public class MainActivity extends AppCompatActivity {
private List<Number> numbers = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initNumber();//自定义了一个函数,用于加载数据
NumberAdapter numberArrayAdapter = new NumberAdapter(MainActivity.this,R.layout.number_item, numbers);
ListView listView = (ListView)findViewById(R.id.list_view);
listView.setAdapter(numberArrayAdapter);
}
}
private void initNumber(){
Number one = new Number("1",R.drawable.small_707);
Number two = new Number("2",R.drawable.small_708);
Number three = new Number("3",R.drawable.small_709);
Number four = new Number("4",R.drawable.small_710);
Number five = new Number("5",R.drawable.small_711);
Number six = new Number("6",R.drawable.small_712);
Number seven = new Number("7",R.drawable.small_713);
Number eight = new Number("8",R.drawable.small_714);
Number nine = new Number("9",R.drawable.small_715);
numbers.add(one);
numbers.add(two);
numbers.add(three);
numbers.add(four);
numbers.add(five);
numbers.add(six);
numbers.add(seven);
numbers.add(eight);
numbers.add(nine);
}
三、对自定义适配器NumberAdapter的优化
1.0
在上面的代码中,每次调用view都要重新加载,我们可以通过判断view是否存在直接调用已经存在的view。即如果convertView为null,就用LayoutInflatr去加载布局,如果
不为null就直接对convertView进行重用。
(关于convertView是什么,参考: http://blog.csdn.net/bill_ming/article/details/8817172)
这时候虽然避免了 布局的重复加载,在if else 外每次都对ImageView和TextView进行控件的实例化。
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Number number = getItem(position);
//不需要重新加载已存在的布局
View view;
if (convertView == null){
view = LayoutInflater.from(getContext()).inflate(id, parent, false);
}else {
view = convertView;
}
ImageView numberImage = (ImageView)view.findViewById(R.id.number_image);
TextView numberName = (TextView)view.findViewById(R.id.number_name);
numberImage.setImageResource(number.getId());
numberName.setText(number.getName());
return view;
}
2.0
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Number number = getItem(position);
View view;
ViewHolder viewHolder;
if (convertView == null){
view = LayoutInflater.from(getContext()).inflate(id, parent, false);//加载布局
viewHolder = new ViewHolder();
viewHolder.imageNumber = view.findViewById(R.id.number_image);
viewHolder.nameNumber = view.findViewById(R.id.number_name);
view.setTag(viewHolder);//将viewHolder储存在view中
}else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();//重新获取viewHolder
}
viewHolder.imageNumber.setImageResource(number.getId());
viewHolder.nameNumber.setText(number.getName());
return view;
}
class ViewHolder {
ImageView imageNumber;
TextView nameNumber;
}
新增了一个内部类ViewHolder,用于对控件进行缓存。当convertView为null的时候,创建新的ViewHolder对象,并将控件的实例储存在view里面。当convertView不为null的时候,就调用getTag()重新获取ViewHolder。就避免了每次通过findviewbyid的方法获取控件实例了。
四、添加响应事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Number number = numbers.get(i);
Toast.makeText(MainActivity.this, number.getName(), Toast.LENGTH_SHORT).show();
}
});