适配器

适配器适配器实现过程:共3步:新建适配器-->添加数据源到适配器-->视图加载适配器适配器的数据源:ArrayAdapter:可以使数组或集合SimpleAdapter:只能是特定泛型的集合BaseAdapter:是一个抽象类,需要自己写一个类继承它。灵活性高,因为提供了4个方法去重写。其中有一个getView()方法,我们可以重写优化ListView的方法。SimpleAdapter是其子类。1.创建ArrayAdapter:public class Test1 extends Activity {    private ListView mListView;    private ArrayAdapterarr_Adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.test1);        //准备好视图,我们的目标ListView        mListView = (ListView) findViewById(R.id.id_listView);        //准备好数据源(数组或集合)        String [] arr = {"Android_1","Android_2","Android_3","Android_4"};        //ArrayAdapter传入3个参数: 上下文,当前ListView加载的“每一个列表项所对应的布局文件”,数据源        //此例用了一个自带的布局文件,Ctrl+左键可以看到这其实是一个简单的TextView,ArrayAdapter功能有限,每个列表项布局只能是TextView        arr_Adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, arr);        mListView.setAdapter(arr_Adapter);    }}2.创建SimpleAdapterSimpleAdapter不同ArrayAdapter每一个列表项只能显示TextView,它每一个列表项可以自己定义各种内容,所以一般需要自己创建布局。res/layout/item.xml:代码部分:(1)根据需要定义ListView每一个列表项所实现的布局(上面已写)。(2)定义一个HashMap构成的列表,将数据以键值对的方式存放在里面。(3)构造SimpleAdapter对象。(4)将LsitView绑定到SimpleAdapter上。public class Test2 extends Activity {    private ListView mListView;    private SimpleAdapter sim_Adapter;    private List> datalist;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.test2);        //准备好视图        mListView = (ListView) findViewById(R.id.id_listView);        //准备好数据源        datalist = new ArrayList>();        /** SimpleAdapter传入3个参数:        * Context:上下文        * data:数据源(List> data),是一个特定泛型的集合。简单讲就是Map组成的List集合。        *        每一个Map<>对应ListView列表中的一行。        *        每一个Map<>(key-value)中的key必须包含所有在from中指定的key        *      因为SimpleAdapter每一个列表项中既要放图片又要放文字,所以需要一个Map<>组合起来,不同于ArrayAdapter只有文字,数据源是简单的List集合。        * resource:列表项布局文件的id        * from:Map<>中的键;    new String []        * to:填充那些组件(在列表项的布局文件中定义的)  new int []        */        sim_Adapter = new SimpleAdapter(this, getData(), R.layout.item, new String []{"pic","text"}, new int[]{R.id.pic, R.id.text});        mListView.setAdapter(sim_Adapter);    }    //通过方法返回数据源,更加灵活    private List> getData() {        for(int i= 0 ; i<20; i++){            Mapdata = new HashMap();            //这里每一Map的键就是第4个参数声明的键,每一个Map的值就是第5个参数声明的组件类型,只不过此处要传入组件具体的显示内容            data.put("pic", R.drawable.ic_launcher);            data.put("text", "Android"+i );            //遍历每一个Map,添加到List集合中去            datalist.add(data);        }        return datalist;    }    }3.创建BaseAdapter(及性能优化)使用BaseAdapter必须写一个类继承它,BaseAdapter是一个抽象类,继承它必须实现它的方法。BaseAdapter的灵活性就在于它要重写4种方法。原理:当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。重点是getView()方法 (常被用于优化):getView()在每一个列表项被滚动到屏幕内的时候被调用,然后new一个View出来作为列表项的布局。假如有10000个列表项,就new 10000次 View出来吗?这肯定会极大的消耗资源,导致ListView滑动非常的慢。convertView(每个列表项的布局,即View):ListView第一次显示的时候,此时convertView是null,getView()会加载一个屏幕所有列表项的View,加载完convertView便不为null。然后在ListView滑动的过程中,会有列表项被滑出屏幕,它所对应的布局convertView便不再给它使用。所以我们可以对convertView进行复用,把失去原主人(旧列表项)的convertView赋给新出来的列表项。View view;if (convertView == null){    view = inflater.inflate(R.layout.item_addmore, null);}else{    view = convertView;}ViewHolder上面的优化仅仅复用了View,但是要得到其中的控件,需要在控件的容器中通过findViewById的方法来获得。当convertView为null时,创建一个ViewHolder对象,并将控件的实例都存放在ViewHolder对象里。这样所有控件的实例都缓存在ViewHolder里。setTage(), getTag()实例缓存好了,怎么给View使用呢?当convertView为null时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。当convertView不为null,重复利用已经创建的view的时候,使用getTag()方法获取绑定的ViewHolder对象,这样就避免了findViewById对控件的层层查询。public class MyAdapter extends BaseAdapter {    ArrayListapk_list;    LayoutInflater inflater;    public MyAdapter(Context context, ArrayListapk_list) {        this.apk_list = apk_list;        this.inflater = LayoutInflater.from(context);    }    //返回值表示该Adapter共包含多个列表项    @Override    public int getCount() {        return apk_list.size();    }    //返回值表示第position处的列表项的内容    @Override    public Object getItem(int position) {        return apk_list.get(position);    }    //返回值表示第position处的列表项的id    @Override    public long getItemId(int position) {        return position;    }    //返回的view将作为列表框布局    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ApkEntity entity = apk_list.get(position);        ViewHolder holder;        if (convertView == null){            holder = new ViewHolder();            convertView = inflater.inflate(R.layout.item_addmore, null);            //得到各个控件的对象,并缓存到View中            holder.name_tv = (TextView) convertView                    .findViewById(R.id.item3_apkname);            holder.des_tv = (TextView) convertView                    .findViewById(R.id.item3_apkdes);            holder.info_tv = (TextView) convertView                    .findViewById(R.id.item3_apkinfo);            convertView.setTag(holder);        }else{            holder = (ViewHolder) convertView.getTag();        }            holder.name_tv.setText(entity.getName());        holder.des_tv.setText(entity.getDes());        holder.info_tv.setText(entity.getInfo());        return convertView;    }    //布局里的控件    class ViewHolder {        TextView name_tv;        TextView des_tv;        TextView info_tv;    }}监听器ListView中主要有2种监听器:OnItemClickListener: 处理视图中单个条目的点击事件。(OnItemSelectedListener,参数与其一致,只是监听用户手指行为不同)OnScrollListener:监听滚动变化,可以用于视图滚动中加载数据。关于OnItemClickListener中4个参数:举个例子解释:有X, Y两个listview,X里有1,2,3,4这4个item,Y里有a,b,c,d这4个item。如果点了b这个item,那么:1.parent 相当于listview Y适配器的一个指针,可以通过它来获得Y里装着的一切东西,再通俗点就是说告诉你,你点的是Y,不是X 。2.view 是你点b item的view的句柄,就是你可以用这个view,来获得b里的控件的id后操作控件。3.position是b在Y适配器里的位置(生成listview时,适配器一个一个的做item,然后把他们按顺序排好队,在放到listview里,意思就是这个b是第position号做好的)。4.id 是b在listview Y里的第几行的位置(很明显是第2行),大部分时候position和id的值是一样的。关于OnScrollListener中4个参数:滚动时一直回调,直到停止滚动时才停止回调。firstVisibleItem:当前能看见的第一个列表项ID(从0开始)visibleItemCount:当前能看见的列表项个数(小半个也算)totalItemCount:列表项共数    //判断是否滚到最后一行        if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {            isLastRow = true;在SimpleAdapter例子上,加上这两个监听器事件:public class Test2 extends Activity implements OnItemClickListener, OnScrollListener{    private ListView mListView;    private SimpleAdapter sim_Adapter;    private List> datalist;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.test2);        //准备好视图        mListView = (ListView) findViewById(R.id.id_listView);        //准备好数据源        datalist = new ArrayList>();        /** SimpleAdapter传入3个参数:        * Context:上下文        * data:数据源(List> data),是一个特定泛型的集合。简单讲就是Map组成的List集合。        *        每一个Map<>对应ListView列表中的一行。        *        每一个Map<>(key-value)中的key必须包含所有在from中指定的key        *      因为SimpleAdapter每一个列表项中既要放图片又要放文字,所以需要一个Map<>组合起来,不同于ArrayAdapter只有文字,数据源是简单的List集合。        * resource:列表项布局文件的id        * from:Map<>中的键;    new String []        * to:填充那些组件(在列表项的布局文件中定义的)  new int []        */        sim_Adapter = new SimpleAdapter(this, getData(), R.layout.item, new String []{"pic","text"}, new int[]{R.id.pic, R.id.text});        mListView.setAdapter(sim_Adapter);        mListView.setOnItemClickListener(this);        mListView.setOnScrollListener(this);    }    //通过方法返回数据源,更加灵活    private List> getData() {        Mapdata = new HashMap();        for(int i= 0 ; i<20; i++){            //这里每一Map的键就是第4个参数声明的键,每一个Map的值就是第5个参数声明的组件类型,只不过此处要传入组件具体的显示内容            data.put("pic", R.drawable.ic_launcher);            data.put("text", "Android"+i);            //遍历每一个Map,添加到List集合中去            datalist.add(data);        }        return datalist;    }        @Override    public void onItemClick(AdapterViewparent, View view, int position, long id) {        String text = mListView.getItemIdAtPosition(position)+"";        Toast.makeText(this, position +":" +text, Toast.LENGTH_SHORT).show();    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        switch (scrollState) {        case SCROLL_STATE_FLING:            Log.i("Main", "用户手指离开屏幕之前,由于用力滑了一下,视图仍继续向前滑动");            break;        case SCROLL_STATE_IDLE:            Log.i("Main", "视图已经停止滑动");            break;        case SCROLL_STATE_TOUCH_SCROLL:            Log.i("Main", "手指没有离开屏幕,视图正在滑动");            break;        }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,            int visibleItemCount, int totalItemCount) {    }}滚动到底部,刷新添加更多内容:1.自定义ListView//自定义一个ListView,在构造方法里就给底部添加一个布局(加载提示布局)public class LoadListView extends ListView implements OnScrollListener{    View footer;// 底部布局;    boolean isLastRow; //最后一行    boolean isLoading ;// 正在加载;    ILoadListener iLoadListener;    public LoadListView(Context context) {        super(context);        initView(context);    }    public LoadListView(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    public LoadListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        initView(context);    }    //添加底部加载提示布局到ListView              private void initView(Context context) {        LayoutInflater inflater = LayoutInflater.from(context);        footer = inflater.inflate(R.layout.footer_layout, null);        //设置底部布局一开始是隐藏的,只有当滚动到最低端才显示        footer.findViewById(R.id.load_layout).setVisibility(View.GONE);        //给ListView添加底部布局        this.addFooterView(footer);        this.setOnScrollListener(this);    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem,            int visibleItemCount, int totalItemCount) {        //判断是否滚到最后一行            if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {                isLastRow = true;            }        }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        //当滚到最后一行且停止滚动时,显示布局,加载数据        if(isLastRow && scrollState == SCROLL_STATE_IDLE){            if(!isLoading){                isLoading = true;                footer.findViewById(R.id.load_layout).setVisibility(View.VISIBLE);                //(加载更多)使用接口回调的方式(当监听到滑动到底端,只需调用接口的onLoad方法,剩余的操作交给onLoad方法就可以了)                iLoadListener.onLoad();            }        }    }    public void setInterface(ILoadListener iLoadListener){        this.iLoadListener = iLoadListener;    }    //加载更多数据的回调接口    public interface ILoadListener{        public void onLoad();    }    //加载完毕    public void loadComplete(){        isLoading = false;        footer.findViewById(R.id.load_layout).setVisibility(                View.GONE);    }}2.自定义Adapterpublic class MyAdapter extends BaseAdapter {    ArrayListapk_list;    LayoutInflater inflater;    public MyAdapter(Context context, ArrayListapk_list) {        this.apk_list = apk_list;        this.inflater = LayoutInflater.from(context);    }    //刷新ListView,更新UI    public void onDateChange(ArrayListapk_list) {        this.apk_list = apk_list;        this.notifyDataSetChanged();    }    //返回值表示该Adapter共包含多个列表项    @Override    public int getCount() {        return apk_list.size();    }    //返回值表示第position处的列表项的内容    @Override    public Object getItem(int position) {        return apk_list.get(position);    }    //返回值表示第position处的列表项的id    @Override    public long getItemId(int position) {        return position;    }    //返回的view将作为列表框布局    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ApkEntity entity = apk_list.get(position);        ViewHolder holder;        if (convertView == null){            holder = new ViewHolder();            convertView = inflater.inflate(R.layout.item_addmore, null);            //得到各个控件的对象,并缓存到View中            holder.name_tv = (TextView) convertView                    .findViewById(R.id.item3_apkname);            holder.des_tv = (TextView) convertView                    .findViewById(R.id.item3_apkdes);            holder.info_tv = (TextView) convertView                    .findViewById(R.id.item3_apkinfo);            convertView.setTag(holder);        }else{            holder = (ViewHolder) convertView.getTag();        }            holder.name_tv.setText(entity.getName());        holder.des_tv.setText(entity.getDes());        holder.info_tv.setText(entity.getInfo());        return convertView;    }    //布局里的控件    class ViewHolder {        TextView name_tv;        TextView des_tv;        TextView info_tv;    }}3.工具类public class ApkEntity {private String name;private String des;private String info;public String getName() {    return name;}public void setName(String name) {    this.name = name;}public String getDes() {    return des;}public void setDes(String des) {    this.des = des;}public String getInfo() {    return info;}public void setInfo(String info) {    this.info = info;}}4.注意主布局下的ListView改成自定义的ListView5.主代码public class Test3 extends Activity implements ILoadListener {private ArrayListapk_list = new ArrayList();private MyAdapter adapter;private LoadListView listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.test3);    getData();    showListView(apk_list);}private void getData() {    for (int i = 0; i < 10; i++) {        ApkEntity entity = new ApkEntity();        entity.setName("测试程序");        entity.setInfo("50w用户");        entity.setDes("这是很棒的应用!");        apk_list.add(entity);    }}private void getLoadData() {    for (int i = 0; i < 4; i++) {        ApkEntity entity = new ApkEntity();        entity.setName("更多程序");        entity.setInfo("50w用户");        entity.setDes("这是一个神奇的应用!");        apk_list.add(entity);    }}private void showListView(ArrayListapk_list) {

if (adapter == null) {

listView = (LoadListView) findViewById(R.id.id_listView);

listView.setInterface(this);

adapter = new MyAdapter(this, apk_list);

listView.setAdapter(adapter);

}else{

adapter.onDateChange(apk_list);

}

}

//正常情况下,不要加延时,此处只为演示

@Override

public void onLoad() {

Handler handler = new Handler();

handler.postDelayed(new Runnable() {

@Override

public void run() {

//获取更多数据

getLoadData();

//更新listview显示;

showListView(apk_list);

//通知listview加载完毕

listView.loadComplete();

}

}, 2000);

}

}

你可能感兴趣的:(适配器)