码迷,mamicode.com
首页 > 移动开发 > 详细

Android中自定义ListView实现上拉加载更多和下拉刷新

时间:2016-07-14 02:06:47      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:

ListView是Android中一个功能强大而且很常用的控件,在很多App中都有ListView的下拉刷新数据和上拉加载更多这个功能。这里我就简单记录一下实现过程。

实现这个功能的方法不止一个,GitHub上有一些开源库可以使用,但是本着学习的精神,我做的是使用自定义ListView实现这个功能。

思路:谷歌提供的ListView是不能提供下拉刷新和下拉加载的,所以我们就需要重写ListView。在ListView的头部和尾部加上我们的布局文件(progressbar)。

先说上拉加载更多实现原理:

首先先写一个底部布局的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">
 <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:id="@+id/foot_load"
     android:padding="5dp"
     android:gravity="center">
     <ProgressBar
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         style="?android:attr/progressBarStyle"
         />
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="加载中。。。。"
         />
 </LinearLayout>

</LinearLayout>

    写一个自定义ListView继承自ListView实现它的三个构造方法,这里必须实现三个构造方法,不实现的话就无法显示ListView.并且在每个构造方法中都写一个方法用于初始化相关控件。

public class MyListView extends ListView {
public MyListView(Context context) {
        super(context);
        initView(context);
    }
    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }
}

在initView(context)方法中通过LayoutInfalter.from(context).from(你的xml,null);拿到xml。返回一个View对象,ListView中有一个setfootView()方法,使用他可以设置View到ListView的底部,当然做了这两步是完全不够的,我们还需要对这个View做一个交互的操作,当用户滑到底部时这个View显示,数据加载完毕之后这个View消失。

第一步:需要对这个底部footView隐藏:

第一种方式是通过setVisibility(View.GONE)这个方法让这个View不显示。

第二种方式:

       //测量footview的高度,通过measure()传入两个0参数,系统会不认这个0,自动帮我们测量出加在底部View的长度信息
        footview.measure(0,0);
        //拿到高度
        footViewHeight=footview.getMeasuredHeight();
        //隐藏view,让头部显示高度为实际测量高度的负数,实现布局的隐藏
        footview.setPadding(0,-footViewHeight,0,0);

第二部:当滑到底部的时候显示这个footView。这里就要实现下滑监听接口implements AbsListView.OnScrollListener,实现接口的两个方法。

  @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (totaItemCounts==lasstVisible&&scrollState==SCROLL_STATE_IDLE) {
            if (!isLoading) {
                isLoading=true;
               // footview.findViewById(R.id.foot_load).setVisibility(View.VISIBLE);
                footview.setPadding(0,0,0,0);
                //加载数据
                loadListener.onLoad();}
        }

    }
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//最后一个可见item是第一个可见item加上所有可见item(第一个可见item为0)
this.lasstVisible=firstVisibleItem+visibleItemCount;
//所有item为listview的所有item
this.totaItemCounts=totalItemCount; }

那么如何在刷新的时候通知ListView加载数据呢?这里使用一个接口回调的方法在自定义ListView写一个接口,里面写一个更新ListView的方法,让主布局调用这个接口实现这个接口的方法。

 public void setInterface(LoadListener loadListener){
        this.loadListener=loadListener;

    }
    //接口回调
    public interface LoadListener{

        void onLoad();
        
  }
    @Override
    public void onLoad() {
        //设置三秒延迟模仿延时获取数据
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //加载数据
                for (int j=1;j<11;j++){

                    list.add(j);
                }
                //更新 数据
                adapter.notifyDataSetChanged();
                //加载完毕,就是让View隐藏
                listview.loadComplete();

            }
        },3000);
}

好了,这就实现了一个简单的上拉加载功能。

下拉刷新和上拉加载过程差不多,但是有时候,下拉刷新有提示,下拉刷新,松开刷新,正在刷新提示,这又该如何实现呐,这里就需要实现onTouchEvent方法,设置下拉长度匹配刷新数据。同时,设置progrebar的可见状态。

   @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                yload=(int)ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY=(int)ev.getY();
                int paddingY=-headViewHeight+(moveY-yload)/2;

                    if (paddingY<0){
                        updateInfo.setText("下拉刷新。。。");
                        progressBar.setVisibility(View.GONE);
                    }
                    if (paddingY>0){
                        updateInfo.setText("松开刷新。。。");
                        progressBar.setVisibility(View.GONE);
                    }

                headview.setPadding(0,paddingY,0,0);

                break;
//            case MotionEvent.ACTION_UP:
//                headview.setPadding(0,0,0,0);
//                updateInfo.setText("正在刷新。。。");
//                progressBar.setVisibility(View.VISIBLE);
//                loadListener.pullLoad();
//
//                break;
        }
        return super.onTouchEvent(ev);
    }

附上完整源码:

main.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.yakir.view.MyListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list_view"></com.yakir.view.MyListView>


</RelativeLayout>

main activity:

package com.yakir.demo;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;

import com.yakir.view.MyListView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements MyListView.LoadListener{
    private MyListView listview;
    private List<Integer>list=new ArrayList<>();
    private ArrayAdapter adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for (int i=1;i<20;i++){
            list.add(i);
        }
        initView();
        adapter=new ArrayAdapter<>(this,android.R.layout.simple_expandable_list_item_1,list);
        listview.setAdapter(adapter);

    }

    private void initView() {
        listview=(MyListView) findViewById(R.id.list_view);
        listview.setInterface(this);
    }

    @Override
    public void onLoad() {
        //设置三秒延迟模仿延时获取数据
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //加载数据
                for (int j=1;j<11;j++){

                    list.add(j);
                }
                //更新 数据
                adapter.notifyDataSetChanged();
                //加载完毕
                listview.loadComplete();

            }
        },3000);


    }

    @Override
    public void pullLoad() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                list.clear();
                for (int i=1;i<20;i++){
                    list.add(i+1);
                }
                adapter.notifyDataSetChanged();
                listview.loadComplete();

            }
        },2000);

    }
}

头布局headview:

<?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"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/head"
        android:orientation="horizontal"
        android:gravity="center"
        android:padding="5dp">
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyleInverse"
            android:id="@+id/progressbar"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="正在刷新。。。。"
            android:id="@+id/update_info"/>

    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/update_time"
            />

    </LinearLayout>


</LinearLayout>

尾布局footview:

<?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">
 <LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:id="@+id/foot_load"
     android:padding="5dp"
     android:gravity="center">
     <ProgressBar
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         style="?android:attr/progressBarStyle"
         />
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="加载中。。。。"
         />
 </LinearLayout>

</LinearLayout>

自定义ListView:

package com.yakir.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.yakir.demo.R;

import java.text.SimpleDateFormat;

/**
 * 自定义listview实现上拉刷新下拉加载
 * Created by qbqw7 on 2016/7/12.
 */
public class MyListView extends ListView implements AbsListView.OnScrollListener{
    private View footview;
    private View headview;
    private int totaItemCounts;
    private int lasstVisible;
    private int fistVisiable;
    private LoadListener loadListener;
    private int footViewHeight;
    private int headViewHeight;
    private int yload;
    boolean isLoading;
    private TextView updateInfo;
    private TextView updateTime;
    private ProgressBar progressBar;
    public MyListView(Context context) {
        super(context);
        initView(context);
    }
    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        //拿到头布局xml
        headview=LayoutInflater.from(context).inflate(R.layout.head_layouyt,null);
        updateInfo=(TextView)headview.findViewById(R.id.update_info);
        updateTime=(TextView)headview.findViewById(R.id.update_time);
        progressBar=(ProgressBar)headview.findViewById(R.id.progressbar);
        updateTime.setText("更新于:"+new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss").format(System.currentTimeMillis()));
        //拿到尾布局xml
        footview=LayoutInflater.from(context).inflate(R.layout.proces_layout,null);
        //测量footview的高度
        footview.measure(0,0);
        //拿到高度
        footViewHeight=footview.getMeasuredHeight();
        //隐藏view
        footview.setPadding(0,-footViewHeight,0,0);
        headview.measure(0,0);
        headViewHeight=headview.getMeasuredHeight();
        headview.setPadding(0,-headViewHeight,0,0);
        //设置不可见
        // footview.findViewById(R.id.foot_load).setVisibility(View.GONE);
        // headview.findViewById(R.id.head).setVisibility(View.GONE);
        //添加到listview底部
        this.addFooterView(footview);
        //添加到listview头部
        this.addHeaderView(headview);
        //设置拉动监听
        this.setOnScrollListener(this);


    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                yload=(int)ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY=(int)ev.getY();
                int paddingY=-headViewHeight+(moveY-yload)/2;

                    if (paddingY<0){
                        updateInfo.setText("下拉刷新。。。");
                        progressBar.setVisibility(View.GONE);
                    }
                    if (paddingY>0){
                        updateInfo.setText("松开刷新。。。");
                        progressBar.setVisibility(View.GONE);
                    }

                headview.setPadding(0,paddingY,0,0);

                break;
//            case MotionEvent.ACTION_UP:
//                headview.setPadding(0,0,0,0);
//                updateInfo.setText("正在刷新。。。");
//                progressBar.setVisibility(View.VISIBLE);
//                loadListener.pullLoad();
//
//                break;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (totaItemCounts==lasstVisible&&scrollState==SCROLL_STATE_IDLE) {
            if (!isLoading) {
                isLoading=true;
               // footview.findViewById(R.id.foot_load).setVisibility(View.VISIBLE);
                footview.setPadding(0,0,0,0);
                //加载数据
                loadListener.onLoad();

            }
        }
        if (fistVisiable==0){
            headview.setPadding(0,0,0,0);
            updateInfo.setText("正在刷新。。。");
            progressBar.setVisibility(View.VISIBLE);
            loadListener.pullLoad();
        }
    }



    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.fistVisiable=firstVisibleItem;
        this.lasstVisible=firstVisibleItem+visibleItemCount;
        this.totaItemCounts=totalItemCount;

    }
    //加载完成
    public void loadComplete(){
        isLoading=false;
        //footview.findViewById(R.id.foot_load).setVisibility(View.GONE);
        footview.setPadding(0,-footViewHeight,0,0);
        headview.setPadding(0,-headViewHeight,0,0);


    }
    public void setInterface(LoadListener loadListener){
        this.loadListener=loadListener;

    }
    //接口回调
    public interface LoadListener{

        void onLoad();
        void pullLoad();


    }
}

 

Android中自定义ListView实现上拉加载更多和下拉刷新

标签:

原文地址:http://www.cnblogs.com/lovelyYakir/p/5668331.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!