PullToRefresh实现下拉刷新和上拉加载更多的ListView

使用PullToRefresh实现下拉刷新和上拉加载更多的ListView效果如下:


PullToRefresh是非常好用的第三方下拉刷新库,它支持:

1.ListView

2.ExpandableListView

3.GridView

4.WebView

等多种常用的需要刷新的View控件,基本上能够满足我们的开发需要。

下面结合一个小Demo介绍一下使用PullToRefresh实现下拉刷新和上拉加载更多的ListView的方法:

(一) 先到GitHub上下载PullToRefresh的类库,下载地址是:

https://github.com/chrisbanes/Android-PullToRefresh

(二) 解压缩后,导入library到自己的工程目录下,然后让使用此功能的Module与library建立依赖。

library给我们提供了常用控件的实现代码,我们可以参照这些代码来自己开发:

PullToRefresh实现下拉刷新和上拉加载更多的ListView_第1张图片


(三) 如何理解下拉刷新和上拉加载更多?

我感觉这段说的很到位:

     下拉刷新是重新加载列表,重新请求数据;而上拉加载更多,是在已有列表的基础上,根据当前客户端显示的最后一个item的ID值,找到后续的若干个Item数据,返回给客户端,添加到当前列表的末尾显示的;就发送请求和返回数据的技术而言,没有区别,区别在SQL语句;还有对于Listview是重置列表数据,还是添加数据到列表末尾的问题。


(四)setMode 设置模式:

  • Mode.BOTH:同时支持上拉下拉
  • Mode.PULL_FROM_START:只支持下拉Pulling Down
  • Mode.PULL_FROM_END:只支持上拉Pulling Up
  • DISABLED 不支持刷新功能

也可以用 ptr:ptrMode="both"

可选值为:disabled(禁用下拉刷新),pullFromStart(仅支持下拉刷新),pullFromEnd(仅支持上拉刷新),both(二者都支持),manualOnly(只允许手动触发)

如果Mode设置成Mode.BOTH,需要设置刷新Listener为OnRefreshListener2,并实现onPullDownToRefresh()、onPullUpToRefresh()两个方法。 

如果Mode设置成Mode.PULL_FROM_START或Mode.PULL_FROM_END,需要设置刷新Listener为OnRefreshListener,同时实现onRefresh()方法。

当然也可以设置为OnRefreshListener2,但是Mode.PULL_FROM_START的时候只调用onPullDownToRefresh()方法,Mode.PULL_FROM的时候只调用onPullUpToRefresh()方法.

如果想上拉、下拉刷新的时候 做一样的操作,那就用OnRefreshListener,上拉下拉的时候都调用

如果想上拉、下拉做不一样的的操作,那就在setOnRefreshListener时 用new OnRefreshListener2


(五) 实现上面效果的代码:

①MainActivity代码:

/**
 * 下拉刷新,上拉加载更多
 * 上拉加载更多,数据量大需要分页,减少内消耗。避免用户快速向下滑动,减少流量
 * 下拉刷新,用户习惯
 * 使用第三方  Xlistview  pulltorefreshlistview
 * 官方(下拉刷新,但是没有上拉加载更多)
 * pulltorefreshview其实都是一个自定义的布局,里面包裹着Listview或者其他的控件
 */
public class MainActivity extends AppCompatActivity {

    protected PullToRefreshListView mPullToRefreshList;
    private MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.setContentView(R.layout.activity_main);
        initView();
        //第一次加载数据,默认我下拉刷新
        initData(false);
        /**
         * 设置模式
         * DISABLED 不启用刷新功能
         * PULL_FROM_START 仅支持下拉
         * PULL_FROM_END 仅支持上拉
         * BOTH  支持上拉和下拉
         * MANUAL_REFRESH_ONLY  不支持手势刷新,但是支持使用点击或者其他动作通过代码手动调用刷新
         *
         */
        mPullToRefreshList.setMode(PullToRefreshBase.Mode.BOTH);

        //如果mode为both时(即有两种状态),使用这个监听
        mPullToRefreshList.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2() {
            //开始下拉  我们需要在用户下拉的时候重新做http请求
            @Override
            public void onPullDownToRefresh(PullToRefreshBase refreshView) {
                initData(false);
            }

            @Override
            public void onPullUpToRefresh(PullToRefreshBase refreshView) {

                initData(true);
            }
        });

        mAdapter = new MyAdapter();
        mPullToRefreshList.setAdapter(mAdapter);

        //如果需要自定义头标题,先拿到原生控件,在原生控件的基础上添加头标题
        //ListView refreshableView = mPullToRefreshList.getRefreshableView();
        //refreshableView.addHeaderView(null);

        //获取一个头部和尾部的布局
        ILoadingLayout loadingLayoutProxy = mPullToRefreshList.getLoadingLayoutProxy();
        loadingLayoutProxy.setRefreshingLabel("正在刷新..."); // 刷新时
        loadingLayoutProxy.setPullLabel("下拉刷新"); // 刚下拉时,显示的提示
        loadingLayoutProxy.setLoadingDrawable(getResources().getDrawable(R.mipmap.ic_launcher));
        loadingLayoutProxy.setLastUpdatedLabel("刚刚"); //一般是上次刷新的时间
        loadingLayoutProxy.setReleaseLabel("松手开始刷新");
    }

    private void initView() {
        mPullToRefreshList = (PullToRefreshListView) findViewById(R.id.pullToRefresh);
    }

    //要获取实体类中的数据
    private List mResult = new ArrayList<>();

    /**
     * 获取数据,参数为判断是上拉加载更多,还是下拉刷新
     */
    private void initData(final boolean isUP) {
        //使用xutils获取网络数据
        HttpUtils httpUtils = new HttpUtils();
        String url = "http://api.shigeten.net/api/Critic/GetCriticList";
        httpUtils.send(HttpRequest.HttpMethod.GET, url, new RequestCallBack() {
            @Override
            public void onSuccess(ResponseInfo responseInfo) {
                //使用Gson解析之前需导包
                Gson gson = new Gson();
                ListData listData = gson.fromJson(responseInfo.result, ListData.class);
                List result = listData.getResult();

                if (isUP) { //上拉加载更多
                    mResult.addAll(result);
                    mAdapter.setResults(mResult);
                    mAdapter.notifyDataSetChanged();
                } else { //下拉刷新
                    mAdapter.setResults(result);
                    mAdapter.notifyDataSetChanged();
                }

                //刷新完成提供给我们手动调用
                mPullToRefreshList.onRefreshComplete();
                Toast.makeText(MainActivity.this, "数据请求成功", Toast.LENGTH_SHORT).show();

            }

            @Override
            public void onFailure(HttpException error, String msg) {
                Log.e("onFailure", error.getMessage());
            }
        });
    }
}

注:上面的代码用到了第三方框架xUtils和和Gson,需要提前把这两个包导入。


②对应的自定义适配器代码:

public class MyAdapter extends BaseAdapter {

    List results;
    public void setResults(List results) {
        this.results = results;
    }

    @Override
    public int getCount() {
        return results == null ? 0 : results.size();
    }

    @Override
    public Object getItem(int position) {
        return results.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null){
            convertView = View.inflate(parent.getContext(),R.layout.item,null);

            holder = new ViewHolder();
            holder.iv = (ImageView) convertView.findViewById(R.id.img);
            holder.tv = (TextView) convertView.findViewById(R.id.text);

            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        ListData.ResultEntity resultEntity = results.get(position);
        holder.tv.setText(resultEntity.getTitle());

        BitmapUtils bitmapUtils = new BitmapUtils(parent.getContext());
        bitmapUtils.display(holder.iv, "http://api.shigeten.net/" + resultEntity.getImage());

        return convertView;
    }

    class ViewHolder{
        private TextView tv;
        private ImageView iv;
    }
}


③对应的要解析的数据的实体类代码:

public class ListData {

    /*
     * status : 0
     * errMsg : null
     */

    private int status;
    private Object errMsg;
    /**
     * id : 100045
     * type : 1
     * publishtime : 636107040000000000
     * title : 《瑞士军刀男》人生已经如此艰难,就不要拆穿
     * summary : 看似荒诞,实则厚重。生与死的距离其实真的不远,自我认知与自我救赎也只是一线之隔。不知道有没有人和我一样,看到最后尸体踏浪而去的时候内心澎湃不已。
     * image : images/B0181F9BC6EFC33D0396A16556952710.jpg
     */

    private List result;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public Object getErrMsg() {
        return errMsg;
    }

    public void setErrMsg(Object errMsg) {
        this.errMsg = errMsg;
    }

    public List getResult() {
        return result;
    }

    public void setResult(List result) {
        this.result = result;
    }

    public static class ResultEntity {
        private int id;
        private int type;
        private long publishtime;
        private String title;
        private String summary;
        private String image;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public long getPublishtime() {
            return publishtime;
        }

        public void setPublishtime(long publishtime) {
            this.publishtime = publishtime;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getSummary() {
            return summary;
        }

        public void setSummary(String summary) {
            this.summary = summary;
        }

        public String getImage() {
            return image;
        }

        public void setImage(String image) {
            this.image = image;
        }
    }
}

④主布局代码activity_main.xml:




    


⑤条目布局,item.xml:



    
    


你可能感兴趣的:(android)