Android Demo之旅 ListView底部添加加载更多按钮实现数据分页

来源:互联网 发布:大数据服务器 编辑:程序博客网 时间:2024/05/16 05:33

在我们的实际项目中,数据应该说是很多的,我们的ListView不可能一下子把数据全部加载进来,我们可以当滚动条滚动到ListView的底部的时候,给一个更多的提示,当我们点击它即加载下一页的数据,相当与我们的分页效果,参考网上的东西,写了一个小小的demo,并总结了一些知识点,功能图如下:

  

源代码下载地址:http://download.csdn.net/detail/harderxin/7762625

掌握知识点:

1)自定义Adapter,将数据和ListView绑定起来

2)理解LayoutInflater动态加载xml布局的用法

3)Handler机制  4)ListView滚动事件

详细的代码大家可以在我的资源中进行下载,下面给大家说一下核心代码的实现:

1、我们定义的Activity继承自ListActivity,我们也可以在xml中定义ListView,然后通过findViewById获取,初始化:

    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        handler=new Handler();        //继承ListActivity,所以可以用这个方法取得        listView=getListView();        initData();        //添加底部按钮        View bottomView=getLayoutInflater().inflate(R.layout.bottom, null);        loadMore=(Button)bottomView.findViewById(R.id.load);        loadMore.setOnClickListener(new ButtonClickListener());                listView.addFooterView(bottomView);        //setListAdapter(adapter);        listView.setAdapter(adapter);        //给listView设置事件        listView.setOnItemClickListener(new OnItemListener());        listView.setOnScrollListener(new OnScrollListener());    }

我们的底部按钮可以通过listView.addFooterView(View view);加载进来,定义我们的按钮布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal" >   <Button        android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:id="@+id/load"       android:text="加载更多"/></LinearLayout>
然后我们可以通过View bottomView=getLayoutInflater().inflate(R.layout.bottom, null);获得View对象,然后通过View对象的findViewById获得我们的按钮:loadMore=(Button)bottomView.findViewById(R.id.load);

2)初始化数据,在里面我们初始化数据为10条,并实例化我们自定义的适配器MyAdapter

    public void initData(){    List<Integer> datas=new ArrayList<Integer>();        for(int i=0;i<10;i++){        datas.add(i+1);        }        adapter=new MyAdapter(datas, this);    }

3)自定义适配器MyAdapter:ListView在界面初始化或者滚动加载的时候,里面的getCount、getView等方法会被时时调用执行,每绘制ListView的一行,就会调用getView一次,然后取得相应的组件添加进去;

package com.xin.activity;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;public class MyAdapter extends BaseAdapter{private List<Integer> datas;private LayoutInflater flater;//构造函数public MyAdapter(List<Integer> datas,Context context){this.datas=datas;flater=LayoutInflater.from(context);}//得到数据总数@Overridepublic int getCount() {System.out.println("aaa");return datas.size();}//得到每一条数据@Overridepublic Object getItem(int position) {return datas.get(position);}//得到项目的位置@Overridepublic long getItemId(int position) {return position;}/** * ListView中所显示的item都是通过调用Adapter对象的getView方法来得到一个View对象 * 然后把这个View对象放在这个item中,这样的一个过程,这就是ListView和Adapter之间的关系 */@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if(convertView==null){//生成一个LayoutInflater对象//inflater=LayoutInflater.from(context);//调用LayoutInflater对象的inflate方法生成一个view对象//LayoutInflater 填充器,通过一个xml对象来填充ListView//inflate作用:填充一个新的视图层次结构从指定的XML资源文件中//参数:View的layout的ID、生成的层次结构的根视图//return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的XML文件的根就是根视图。convertView=flater.inflate(R.layout.list, null);//生成ViewHolder对象viewHolder=new ViewHolder();//将convertView中的相关组件赋给ViewHolder中的成员变量viewHolder.img=(ImageView)convertView.findViewById(R.id.img);viewHolder.info=(TextView)convertView.findViewById(R.id.info);//设置tagconvertView.setTag(viewHolder);}else{//从convertView中得到我们的viewHolderviewHolder=(ViewHolder)convertView.getTag();}//给viewHolder中的组件添加相应的属性viewHolder.img.setBackgroundResource(R.drawable.ic_launcher);viewHolder.info.setText("选项"+datas.get(position));return convertView;}//ViewHolder类,保存我们的组件信息,其中的变量值为我们在xml中定义的组件信息,//当我们的View通过convertView=flater.inflate(R.layout.list, null);生成出来后//我们就可以在convertView取得ViewHolder组件中的相关信息,而不需要重新inflate一遍,减少内存的使用class ViewHolder{private ImageView img;private TextView info;}//添加数据public void addItem(Integer i){datas.add(i);}}
ListView中每一行的xml布局:通过convertView=flater.inflate(R.layout.list, null);得到View,然后得到里面相应的组件一条一条的添加到ListView中,

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:orientation="horizontal" >    <ImageView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/img"/>    <TextView         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/info"/>    </LinearLayout>


4)点击按钮加载我们的数据,在这里主要用到的方法是adapter.notifyDataSetChanged();它会通知适配器数据的变化

使用Handler中postDelayed方法,延迟2000毫秒执行里面的代码,虽然用到了Runnable类,但是它也是运行在主线程中的,并没有另外开启一个线程;

    class ButtonClickListener implements OnClickListener{@Overridepublic void onClick(View v) {loadMore.setText("数据加载中");handler.postDelayed(new Runnable() {@Overridepublic void run() {System.out.println("hello");loadData();adapter.notifyDataSetChanged();//listView.setSelection(5);loadMore.setText("加载更多");}}, 2000);}    }        //加载数据    public void loadData(){    int count=adapter.getCount()+1;    for(int i=count;i<count+10;i++){    adapter.addItem(i);    }    }

5)ListView中的事件:

单击一行事件:

    /**     * 单击ListView中某一项触发的事件     * @author dell     *     */    class OnItemListener implements OnItemClickListener{@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int position,long id) {System.out.println("123");}    }
滚动加载事件:

    //是否到达ListView底部    boolean isLastRow=false;    /**     * 滚动时产生的事件     * @author dell     *     */    class OnScrollListener implements android.widget.AbsListView.OnScrollListener{    //滚动的时候一直回调,直到停止滚动时才停止回调,单击时回调一次    //firstVisibleItem:当前嫩看见的第一个列表项ID(从0开始,小半个也算)    //visibleItemCount:当前能看见的列表项个数(小半个也算)    //totalItemCount:列表项总共数@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {System.out.println("firstVisibleItem="+firstVisibleItem);System.out.println("visibleItemCount="+visibleItemCount);//判断是否滚动到最后一行if(firstVisibleItem+visibleItemCount==totalItemCount&&totalItemCount>0){System.out.println("已经到最后一行了");isLastRow=true;}}//正在滚动时回调,回调2-3次,手指没抛则回调2次,scrollState=2的这次不回调//回调顺序如下://第一次:scrollState=SCROLL_STATE_TOUCH_SCROLL(1)正在滚动//第二次:scrollState = SCROLL_STATE_FLING(2)手指做了抛的动作(手指离开屏幕前,用力滑了一下)//第三次:scrollState = SCROLL_STATE_IDLE(0) 停止滚动       //当屏幕停止滚动时为0;当屏幕滚动且用户使用的触碰或手指还在屏幕上时为1;          //由于用户的操作,屏幕产生惯性滑动时为2  @Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {System.out.println("789");//当滚动到最后一行并且停止滚动时,执行加载if(isLastRow&&scrollState==OnScrollListener.SCROLL_STATE_IDLE){//执行加载代码isLastRow=false;}}        }

拓展知识点LayoutInflater:

我们在onCreate方法中总会有:setContentView(R.layout.main);出现,其实也可以使用LayoutInflater来加载:

      setContentView(R.layout.main);        show=(Button)findViewById(R.id.btn);        //下面的方式和上面的方式是等同的        //LayoutInflater layoutInflater=LayoutInflater.from(this);        //View vv=layoutInflater.inflate(R.layout.main, null);        //setContentView(vv);        //show=(Button)vv.findViewById(R.id.btn);
区别是:

setContentView()一旦调用, layout就会立刻显示UI;而inflate只会把Layout形成一个以view类实现成的对象,有需要时再用setContentView(view)显示出来。

一般在activity中通过setContentView()将界面显示出来, 但是如果在非activity中如何对控件布局设置操作了,这就需要LayoutInflater动态加载。

LayoutInflater笔记:

/**
 * 使用LayoutInflater来动态载入AlertDialog页面显示的内容,AlertDialog使用的布局方式在layout目录下定义的custom_dialog.xml
 * 
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。
不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。 
具体作用: 
1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。
什么是已经被载入的layout,什么是还没有载入的.我们启动一个应用,与入口Activity相关的layout{常见的是main.xml}就是被载入的,即在Oncreate()中的.
而其他的layout是没有被载入的.就要动态载入了或通过另一个activity.

LayoutInflater作用是将layout的xml布局文件实例化为View类对象。
获取LayoutInflater的方法有如下三种:
LayoutInflater inflater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.main, null);
LayoutInflater inflater = LayoutInflater.from(context); (该方法实质就是第一种方法,可参考源代码)
View layout = inflater.inflate(R.layout.main, null);
LayoutInflater inflater = getLayoutInflater();(在Activity中可以使用,实际上是View子类下window的一个函数)
View layout = inflater.inflate(R.layout.main, null);
注意:
·inflate方法与 findViewById 方法不同;
·inflater 是用来找 res/layout下的 xml 布局文件,并且实例化;
·findViewById() 是找具体 xml 布局文件中的具体 widget 控件(如:Button、TextView 等)。
 * @author dell
 *
 */

0 0
原创粉丝点击