Adapter是适配器。它的作用是封装好item然后将数据提供给ListView去显示。
Adapter原理分析:
ListView显示的时候,首先会去调用适配器,适配器去数据源读取数据并根据item布局组织成一个item view对象返回在ListView中显示。
ArrayAdapter
ArrayAdapter是最简单的适配器,用于为ListView提供承载简单数据的item界面。它的数据源必须是数组或简单List集合。它加载的item布局中必须包括至少一个TextView控件,数据源中的数据将逐条显示在每一个itemview的TextView控件中。只能用于显示文本数据。
我们用ArrayAdapter来显示国乒七虎将的名字效果如下:
代码如下:
activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/lvFriends"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</ListView>
item.xml
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="30sp"
>
</TextView>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ListView lv;
private ArrayAdapter<String> adapter;
private void setupView(){
//获取ListView实例
lv=(ListView) findViewById(R.id.lvFriends);
//获取数据
String[] heros={"马龙","张继科","许昕","樊振东","方博","闫安","周雨"};
//获得适配器实例
adapter=new ArrayAdapter<String>(this,R.layout.item,heros);
//为ListView控件设置适配器
lv.setAdapter(adapter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();
}
}
SimpleAdapter
SimpleAdapter是一种简单的通用适配器,它的数据源必须是由结构相同的Map集合构成的List集合,每个Map中的数据将被显示在Item中,所以必须为item中的每个控件指定该控件对应显示的值是Map对象中哪个key对应的值。也即需要为Map对象中的key与Item界面中的控件id建立对应关系。
SimpleAdapter的构造方法:
SimpleAdapter(Context context,List<Map<String,Object>> data,int layoutRes,String[] from,int[] to )
-data :必须是由结构相同的Map集合构成的List集合
-layoutRes :item的布局资源id
-from :map集合的key构成的数组
-to :item布局中的控件id构成的数组
我们通过一个例子来说明下它的用法:列表左边显示照片,右边显示姓名
代码如下:
activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</ListView>
item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/ivPhoto"
android:layout_width="80dp"
android:layout_height="80dp"
/>
<TextView
android:id="@+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_gravity="center"
/>
</LinearLayout>
DataSource.java
public class DataSource {
public static List<HashMap<String,Object>> getData(){
List<HashMap<String,Object>> lists=new ArrayList<HashMap<String,Object>>();
HashMap<String,Object> item=new HashMap<String,Object>();
item.put("photo",R.mipmap.w5);
item.put("name","福原爱1");
lists.add(item);
item=new HashMap<String,Object>();
item.put("photo",R.mipmap.w1);
item.put("name","福原爱2");
lists.add(item);
item=new HashMap<String,Object>();
item.put("photo",R.mipmap.w3);
item.put("name","福原爱3");
lists.add(item);
item=new HashMap<String,Object>();
item.put("photo",R.mipmap.w2);
item.put("name","福原爱4");
lists.add(item);
item=new HashMap<String,Object>();
item.put("photo",R.mipmap.w4);
item.put("name","福原爱5");
lists.add(item);
return lists;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private ListView lv;
private SimpleAdapter adapter;
private void setupView(){
lv=(ListView) findViewById(R.id.lv);
//获取数据源
List<HashMap<String,Object>> list=DataSource.getData();
//from与to的顺序要保持一致
String[] from={"photo","name"};
int[] to={R.id.ivPhoto,R.id.tvName};
adapter=new SimpleAdapter(this,list,R.layout.item,from,to);
lv.setAdapter(adapter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();
}
}
自定义Adapter
在Android中,除了使用通用适配器之外,我们还可以通过继承Adapter接口的实现类BaseAdapter的方式来自定义适配器。BaseAdapter中有四个抽象方法必须被实现。其中与列表项显示相关的方法有两个:getCount()方法和getView(int position,View convertView,ViewGroup parent)。其中getCount方法返回数据集长度。而getView方法的作用主要是根据参数position,从数据集中获取指定位置的数据,并将之加载在item界面上返回给ListView。有一些复杂的列表项必须通过自定义Adapter来实现。
在这个程序中,我们对是否加载到最后当前页最后一条做了判断,如果加载到最后一条就继续加载,对列表项单击事件做了处理,在dailog显示学生信息。
代码如下:
activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</ListView>
stu_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/llItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/ic_launcher"
/>
<TableLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0">
<TableRow>
<TextView
android:id="@+id/tvId"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/tvName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"/>
</TableRow>
<TableRow>
<TextView
android:id="@+id/tvSex"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"/>
<TextView
android:id="@+id/tvAge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.0"/>
</TableRow>
</TableLayout>
</LinearLayout>
Student.java
public class Student {
private int id;
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Student(int id, String name, String sex, int age) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
StudentData.java
public class StudentData {
public static List<Student> getData(int page){
int item=(page-1)*10+1;
List<Student> list=new ArrayList<>();
for(int i=item;i<item+10;i++){
Student stu=new Student(i,"同学"+i,"男",18);
list.add(stu);
}
return list;
}
}
StudentAdapter.java
public class StudentAdapter extends BaseAdapter {
private List<Student> stus;
//用于将资源文件实例化成视图树
private LayoutInflater inflater;
private boolean isIdle;
public void setIdle(boolean idle) {
isIdle = idle;
}
public StudentAdapter(Context context, List<Student> list){
if (list.size()>0){
stus=list;
}else{
stus=new ArrayList<Student>();
}
//实例化inflater
inflater=LayoutInflater.from(context);
isIdle=true;
}
public void addData(List<Student> stu){
if(stu!=null){
stus.addAll(stu);//追加数据
notifyDataSetChanged();
}
}
@Override
public int getCount() {
return stus.size();
}
@Override
public Object getItem(int i) {
return stus.get(i);
}
@Override
public long getItemId(int i) {
return stus.get(i).getId();
}
@Override
public View getView(int i, View v, ViewGroup viewGroup) {
ViewHolder holder=null;
//加载或重用item view
if(v==null){
v=inflater.inflate(R.layout.stu_item,null);
holder=new ViewHolder();
holder.tvId= (TextView) v.findViewById(R.id.tvId);
holder.tvName= (TextView) v.findViewById(R.id.tvName);
holder.tvSex= (TextView) v.findViewById(R.id.tvSex);
holder.tvAge= (TextView) v.findViewById(R.id.tvAge);
v.setTag(holder);
}else{
holder=(ViewHolder) v.getTag();
}
if(isIdle) {//停止滑动,加载数据。懒加载模式提高程序的运行效率
//从数据源取出指定位置的数据
Student s = stus.get(i);
//将数据写在item View
holder.tvId.setText("" + s.getId());
holder.tvName.setText(s.getName());
holder.tvSex.setText(s.getSex());
holder.tvAge.setText("" + s.getAge());
}
//将item view对象返回
return v;
}
}
class ViewHolder{
TextView tvId;
TextView tvName;
TextView tvSex;
TextView tvAge;
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
StudentAdapter adapter;
private ListView listView;
private AlertDialog dialog;
private int page=1;
private void addListener(){
//添加滚动事件监听器
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
boolean isLastRow = false;//是否是最后一条
@Override
public void onScrollStateChanged(AbsListView absListView, int i) {
switch (i){//当屏幕停止滚动时为0;;
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
adapter.setIdle(true);
adapter.notifyDataSetChanged();//重新加载数据
break;
//由于用户的操作,屏幕产生惯性滑动时为2
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
adapter.setIdle(false);
break;
//当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1
case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
adapter.setIdle(false);
break;
}
if(isLastRow&&i== AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
//表明已经加载到最后一条
List<Student> list=StudentData.getData(++page);
adapter.addData(list);
isLastRow=false;
}
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
//滚动时一直回调,直到停止滚动时才停止回调。单击时回调一次。
//firstVisibleItem:当前能看见的第一个列表项ID(从0开始)
//visibleItemCount:当前能看见的列表项个数(小半个也算)
//totalItemCount:列表项总数
Log.i("data","i:"+i+",i1"+i1+",i2"+i2);
if(i+i1==i2){
isLastRow=true;
}
}
});
}
private void setupView(){
listView=(ListView) findViewById(R.id.lv);
adapter=new StudentAdapter(this, StudentData.getData(page));
listView.setAdapter(adapter);
dialog=new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_info)
.setTitle("学生详情").setPositiveButton("确定",null).create();
//item view单击事件的监听器
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Log.i("msg","position:"+i+" id:"+l);
Student s= (Student) adapter.getItem(i);
dialog.setMessage(s.toString());
dialog.show();
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setupView();
addListener();
}
}