1. ListView
ListView应该算是Android 中最常见的控件之一了,几乎所有的应用都会用到ListView。y由于我们的手机屏幕空间有限,能够一次性在屏幕中显示的内容不多。当程序中的数据量较多的时候,我们通过使用ListView允许用户通过手指滑动的方式将屏幕外的数据滑动到屏幕内,同时去除掉原有的数据。
1.1 ListView的类结构:
java.lang.Object
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.AdapterView<T extends android.widget.Adapter>
↳ android.widget.AbsSpinner
↳ android.widget.Spinner
1.2 ListView的职责
1.将数据填充到布局当中
2.处理点击事件
1.3 列表显示的三个元素
1.ListView 用于展示列表的元素 ListView
2.适配器 ,将数据和容器连接的桥梁
3.数据源 ,具体的数据
1.4 适配器
适配器是连接数据和容器的桥梁或者通道。通过它能有效的将数据和View实现分离。使得数据的绑定更加的简便。将数据源适配到ListView上的适配器有:ArrayAdapter、SimpleAdapter 和 SimpleCursorAdapter。
● ArrayAdapter最为简单,只能展示一行字;
● SimpleAdapter有最好的扩充性,可以自定义各种各样的布局,除了文本外,还可以放ImageView(图片)、Button(按钮)、CheckBox(复选框)等等;
● SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方便地把数据库的内容以列表的形式展示出来。
● 但是实际工作中,常用自定义适配器。即继承于BaseAdapter的自定义适配器类。
2. ListView的简单用法
假设你有一组数据需要通过ListView显示在屏幕上,你要怎么做呢?
1.首先需要有一个ListView的控件在layout文件上,用于装载数据.新建一个 activity_mylist.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/myList_lv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
2.既然是要装载数据,哪还得有数据,这个数据可以是从网上下载,也可以是从数据库中读取,具体情况视场景而定,这里写了一个数组data,里面包括了学生的姓名。
String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};
3.有了容器和数据了,我们接下来就需要的是将数据装载到容器里面了。这时候需要用到adapter适配器。 适配器的作用是为了将数组数据一个个的装载到容器里面。Android 中提供了许多适配器的实现类,这里用ArrayAdapter ,通过使用泛型来指定要适配的数据类。这里用的是字符串,所以用String 类,然后在ArrayAdapter的构造函数依次传入当前的上下文对象,ListView 项目的子布局,以及适配的数据。最后将数据装载到容器中
public class MainActivity extends AppCompatActivity {
String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mylist);
ListView listView = (ListView) findViewById(R.id.myList_lv);
ArrayAdapter<String > adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,data);
listView.setAdapter(adapter);
}
}
2.1 使用系统自带布局文件的不同效果
1.android.R.layout.simple_list_item_1
只改一个系统布局还不行, 加上这个 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
2.android.R.layout.simple_list_item_checked
ListView listView= (ListView) findViewById(R.id.list3);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_checked,data);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(arrayAdapter);
3.android.R.layout.simple_list_item_multiple_choice
只改一个系统布局还不行, 加上这个 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
ListView listView= (ListView) findViewById(R.id.list3);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_multiple_choice,data);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView.setAdapter(arrayAdapter);
4.simple_list_item_single_choice
ListView listView= (ListView) findViewById(R.id.list3);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_single_choice,data);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
listView.setAdapter(arrayAdapter);
3.ListView的一般用法
在一般的应用中我们可能会加载到图片,实现图文混排的效果。先来张效果图。
3.1 方法一:
实践步骤:
1.每个item 的设计都是 图片+文字这样来处理的,所以首先新建一个layout文件设计子项目的布局 item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center_vertical"
android:padding="10dp">
<ImageView
android:id="@+id/iv_head"
android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@mipmap/ic_launcher"
android:scaleType="centerCrop"/>
<TextView
android:id="@+id/tv_student_name"
android:layout_width="wrap_content"
android:layout_height="80dp"
android:text="学生姓名"
android:layout_gravity="center"
android:gravity="center"/>
</LinearLayout>
2.之前说过加载文件资源需要先提供本地资源,再通过adapter来加载资源
public class MainActivity extends AppCompatActivity {
private ListView listView;
String [] data={"学生一","学生二","学生三","学生四","学生五","学生六","学生七","学生八","学生九","学生十","学生十一","学生十二","学生十三"};
private int [] imagesId={R.mipmap.aa1,R.mipmap.a1,R.mipmap.a2,R.mipmap.a3,R.mipmap.a4,R.mipmap.a5,R.mipmap.a6,R.mipmap.a7,R.mipmap.a8,R.mipmap.a9,R.mipmap.a10,R.mipmap.a11,R.mipmap.a12,R.mipmap.a13};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mylist);
listView = (ListView) findViewById(R.id.myList_lv);
BaseAdapter baseAdapter=new BaseAdapter() {
@Override
public int getCount() {
return data.length;
}
@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) {
//获取行布局
LayoutInflater inflater = getLayoutInflater();
LinearLayout layout = (LinearLayout)inflater.inflate(R.layout.item_list, null);
//行布局中的控件
ImageView image = (ImageView)layout.findViewById(R.id.iv_head);
TextView tv1 = (TextView)layout.findViewById(R.id.tv_student_name);
//更新行布局中的内容
image.setImageResource(imagesId[position]);
tv1.setText(data[position]);
return layout;
}
};
listView.setAdapter(baseAdapter);
}
3.2 方法二:
1.定义一个实体类 Student
public class Student {
private String name;
private int imageId;
public Student(String name, int imageId) {
this.name = name;
this.imageId = imageId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
}
2.创建适配器StudentAdapter
public class StudentAdapter extends ArrayAdapter<Student> {
private int resourceId;
public StudentAdapter(@NonNull Context context, @LayoutRes int resource, List<Student> objects) {
super(context, resource,objects);
resourceId=resource;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Student student=getItem(position);
View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
ImageView studentImage= (ImageView) view.findViewById(R.id.iv_head);
TextView studentname= (TextView) view.findViewById(R.id.tv_student_name);
studentImage.setImageResource(student.getImageId());
studentname.setText(student.getName());
return view;
}
}
3.加载数据
public class MainActivity2 extends AppCompatActivity {
private List<Student> studentList=new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mylist);
initStudent();
StudentAdapter adapter=new StudentAdapter(MainActivity2.this,R.layout.item_list,studentList);
ListView listView= (ListView) findViewById(R.id.myList_lv);
listView.setAdapter(adapter);
}
//通过循环将数据加载到List<Student>当中
//初始化所有的学生数据,通过构造函数将学生名字和对应的图片添加上去,这里循环两边是为了显示更多的数据,显示一遍也可以。
private void initStudent() {
for (int i = 0; i < 2; i++) {
Student student1=new Student("学生一",R.mipmap.a1);
studentList.add(student1);
Student student2=new Student("学生二",R.mipmap.a2);
studentList.add(student2);
Student student3=new Student("学生三",R.mipmap.a3);
studentList.add(student3);
Student student4=new Student("学生四",R.mipmap.a4);
studentList.add(student4);
Student student5=new Student("学生五",R.mipmap.a5);
studentList.add(student5);
Student student6=new Student("学生六",R.mipmap.a6);
studentList.add(student6);
Student student7=new Student("学生七",R.mipmap.a7);
studentList.add(student7);
Student student8=new Student("学生八",R.mipmap.a8);
studentList.add(student8);
Student student9=new Student("学生九",R.mipmap.a9);
studentList.add(student9);
Student student10=new Student("学生十",R.mipmap.a10);
studentList.add(student10);
Student student11=new Student("学生十一",R.mipmap.a11);
studentList.add(student11);
Student student12=new Student("学生十二",R.mipmap.a12);
studentList.add(student12);
Student student13=new Student("学生十三",R.mipmap.a13);
studentList.add(student13);
}
}
}
4.ListView 的优化
ListView有时会比较难用,有很多细节需要优化。
1.getView()方法中的convertView 参数,这个参数是用于将之前加载好的布局进行缓存,以便之后可以进行重用。修改代码:
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Student student=getItem(position);
View view;
if(convertView==null){
view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
}else{
view=convertView;
}
ImageView studentImage= (ImageView) view.findViewById(R.id.iv_head);
TextView studentname= (TextView) view.findViewById(R.id.tv_student_name);
studentImage.setImageResource(student.getImageId());
studentname.setText(student.getName());
return view;
}
通过对convertView进行空判断,使用LayoutInflate 去加载布局。不为空就对convertview进行重用,提高了使用效率。在数据量大,快速滚动的时候性能更优异。
2.新增内部类ViewHolder,用于对控件实例化并进行缓存。然后调用setTag()方法,将ViewHolder对象存储在View中。当convertview不为空的时候,调用View的getTag()方法去除ViewHolder对象。
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Student student=getItem(position);
View view;
ViewHolder holder;
if(convertView==null){
view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);//false 表明我们只让在父布局中的layout生效,但不会为这个View添加父布局(只有孤儿才能被领养)
holder=new ViewHolder();
holder.studentImage=(ImageView) view.findViewById(R.id.iv_head);
holder.studentname=(TextView) view.findViewById(R.id.tv_student_name);
view.setTag(holder);//将viewholder 存储在View中
}else{
view=convertView;
holder= (ViewHolder) view.getTag();
}
holder.studentImage.setImageResource(student.getImageId());
holder.studentname.setText(student.getName());
return view;
}
class ViewHolder{
ImageView studentImage;
TextView studentname;
}
5. ListView的点击事件
如果ListView 只能滚动的话,只满足了视觉上的要求,但是真正的需求是点击事件。只有通过点击选中某个item展示这个item的内容,才是我们所想要的。修改代码:
public class MainActivity2 extends AppCompatActivity {
private List<Student> studentList=new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mylist);
initStudent();
StudentAdapter adapter=new StudentAdapter(MainActivity2.this,R.layout.item_list,studentList);
ListView listView= (ListView) findViewById(R.id.myList_lv);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Student student=studentList.get(position);
Toast.makeText(MainActivity2.this, student.getName(), Toast.LENGTH_SHORT).show();
}
});
}