Android系统上拉刷新功能的实现

清华大佬耗费三个月吐血整理的几百G的资源,免费分享!....>>>

自定义ListView:
public class MyListView extends ListView implements OnScrollListener {
  
    public final int RATIO = 5;// 手拖动时,手指拖动距离与header下移的倍数
    private final int LOADING = 0;// 正在加载
    private final int RELEASE_To_REFRESH = 2;// 正在下拉状态,即将松手进行刷新
    private final int DONE = 3;// 完成
    private final int HIDE_To_REFRESH = 1;// 未下拉或已完成状态,设置padding为负值把header挡住
  
    private int refreshStatus;// 下拉刷新过程状态变量
  
    private LinearLayout hearderLayout;
    private ImageView arrowImageView;
    private ProgressBar progressBar;
    private TextView tipsTextview;
    private TextView lastUpdatedTime;
    private int headContentHeight;
    private int headContentWidth;
    private RotateAnimation animation;
    private RotateAnimation reverseAnimation;
    private boolean isStartRefreshEvent = false;// 下拉刷新事件是否已经开始
    private boolean isRefreshable = false;// 是否设置下拉刷新监听
    private int firstItemIndex;
  
    private OnRefreshListener refreshListener;
  
    public MyListView (Context context) {
        super(context);
        init(context);
    }
  
    public MyListView (Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
  
    private void init(Context context) {
  
        LayoutInflater inflater = LayoutInflater.from(context);
        hearderLayout = (LinearLayout) inflater.inflate(R.layout.list_view_header, null);
        // 下拉箭头
        arrowImageView = (ImageView) hearderLayout.findViewById(R.id.head_arrowImageView);
        // 进度条
        progressBar = (ProgressBar) hearderLayout.findViewById(R.id.head_progressBar);
        // 下拉提示 刷新
        tipsTextview = (TextView) hearderLayout.findViewById(R.id.head_tipsTextView);
        // 最新一次刷新时间
        lastUpdatedTime = (TextView) hearderLayout.findViewById(R.id.head_lastUpdatedTextView);
        // 计算head的高宽
        this.measureView(hearderLayout);
        headContentHeight = hearderLayout.getMeasuredHeight();
        headContentWidth = hearderLayout.getMeasuredWidth();
  
        // 初始状态是 隐藏掉head 布局
        hearderLayout.setPadding(0, -1 * headContentHeight, 0, 0);
        hearderLayout.invalidate();
  
        Log.e("sys", "width:" + headContentWidth + " height:" + headContentHeight);
        // list添加头文件
        addHeaderView(hearderLayout, null, false);
        setOnScrollListener(this);// TODO
        // 下拉以及恢复动画
        animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        animation.setInterpolator(new LinearInterpolator());
        animation.setDuration(250);
        animation.setFillAfter(true);
        reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        reverseAnimation.setInterpolator(new LinearInterpolator());
        reverseAnimation.setDuration(200);
        reverseAnimation.setFillAfter(true);
        refreshStatus = DONE;
    }
  
    @Override
    public void onScroll(AbsListView arg0, int firstVisiableItem, int arg2, int arg3) {
        firstItemIndex = firstVisiableItem;
    }
  
    @Override
    public void onScrollStateChanged(AbsListView arg0, int arg1) {
    }
  
    private int startY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
  
        if (firstItemIndex == 0 && isRefreshable) {
            switch (event.getAction()) {
            // 在down时候记录当前Y的位置
            case MotionEvent.ACTION_DOWN:
                if (!isStartRefreshEvent) {
                    isStartRefreshEvent = true;
                    startY = (int) event.getY();
                }
                break;
  
            case MotionEvent.ACTION_MOVE:
  
                int tempY = (int) event.getY();
                int scrollY = (tempY - startY) / RATIO;
  
                Log.i("sys", "拉开方向 " + scrollY);
  
                if (!isStartRefreshEvent) {
                    isStartRefreshEvent = true;
                    startY = tempY;
                } else if (isStartRefreshEvent && refreshStatus != LOADING) {
                    // 可以松手去刷新了
                    if (refreshStatus == RELEASE_To_REFRESH) {
                        setSelection(0);
                        // header被用户拉下来后,又往上推了,推到了已经小于header高度时,则推回去,并取消刷新
                        if (scrollY < headContentHeight && scrollY > 0) {
                            refreshStatus = HIDE_To_REFRESH;
                            this.changeHeaderView();
                        }
                        // 一下子推到顶了
                        else if (scrollY <= 0) {
                            refreshStatus = DONE;
                            this.changeHeaderView();
                        }
                    }
                    // 还没有到达显示松开刷新的时候,DONE或者是HIDE_To_REFRESH状态
                    if (refreshStatus == HIDE_To_REFRESH) {
                        setSelection(0);
                        // 下拉至超过header本身高度后,可以进入RELEASE_TO_REFRESH的状态
                        if (scrollY > headContentHeight) {
                            refreshStatus = RELEASE_To_REFRESH;
                            this.changeHeaderView();
                        }
                        // 上推到顶了
                        else if (scrollY <= 0) {
                            refreshStatus = DONE;
                            this.changeHeaderView();
                        }
                    }
                    // done状态下
                    if (refreshStatus == DONE) {
                        if (scrollY > 0) {
                            refreshStatus = HIDE_To_REFRESH;
                            this.changeHeaderView();
                        }
                    }
                    // 更新headView的size
                    if (refreshStatus == HIDE_To_REFRESH) {
                        hearderLayout.setPadding(0, -1 * headContentHeight + scrollY, 0, 0);
                    }
                    // 更新headView的paddingTop
                    if (refreshStatus == RELEASE_To_REFRESH) {
                        hearderLayout.setPadding(0, scrollY - headContentHeight, 0, 0);
                    }
                }
                break;
  
            case MotionEvent.ACTION_UP:
                if (refreshStatus != LOADING) {
                    if (refreshStatus == DONE) {
                        // 什么都不做
                    }
                    // 由下拉刷新状态,到done状态
                    if (refreshStatus == HIDE_To_REFRESH) {
                        refreshStatus = DONE;
                        this.changeHeaderView();
                    }
  
                    if (refreshStatus == RELEASE_To_REFRESH) {
                        refreshStatus = LOADING;
                        this.changeHeaderView();
                        onRefresh();
                    }
                }
                isStartRefreshEvent = false;
                break;
  
            }
        }
        return super.onTouchEvent(event);
    }
  
    private void changeHeaderView() {
        switch (refreshStatus) {
        // 松开刷新状态
        case RELEASE_To_REFRESH:
            arrowImageView.setVisibility(View.VISIBLE);
            progressBar.setVisibility(View.GONE);
            tipsTextview.setVisibility(View.VISIBLE);
            lastUpdatedTime.setVisibility(View.VISIBLE);
            arrowImageView.clearAnimation();
            arrowImageView.startAnimation(animation);
            tipsTextview.setText("松开刷新");
            break;
        // 下拉刷新
        case HIDE_To_REFRESH:
            progressBar.setVisibility(View.GONE);
            tipsTextview.setVisibility(View.VISIBLE);
            lastUpdatedTime.setVisibility(View.VISIBLE);
            arrowImageView.setVisibility(View.VISIBLE);
            // 是由RELEASE_To_REFRESH状态转变来的
            arrowImageView.clearAnimation();
            arrowImageView.startAnimation(reverseAnimation);
            tipsTextview.setText("下拉刷新");
            break;
        // 刷新中 状态
        case LOADING:
            hearderLayout.setPadding(0, 0, 0, 0);
            progressBar.setVisibility(View.VISIBLE);
            arrowImageView.clearAnimation();
            arrowImageView.setVisibility(View.GONE);
            tipsTextview.setText("正在刷新...");
            lastUpdatedTime.setVisibility(View.VISIBLE);
            break;
        // 刷新完毕
        case DONE:
            hearderLayout.setPadding(0, -1 * headContentHeight, 0, 0);
            progressBar.setVisibility(View.GONE);
            arrowImageView.clearAnimation();
            // arrowImageView.setImageResource(R.drawable.goicon);
            tipsTextview.setText("下拉刷新");
            lastUpdatedTime.setVisibility(View.VISIBLE);
            break;
        }
    }
  
    public void setonRefreshListener(OnRefreshListener refreshListener) {
        this.refreshListener = refreshListener;
        isRefreshable = true;
    }
  
    public interface OnRefreshListener {
        public void onRefresh();
    }
  
    public void onRefreshFinished() {
        refreshStatus = DONE;
        DateFormat format = new SimpleDateFormat("yyyy年MM月dd日  HH:mm");
        String date = format.format(new Date());
        lastUpdatedTime.setText("最近更新:" + date);
        changeHeaderView();
    }
  
    private void onRefresh() {
        if (refreshListener != null) {
            refreshListener.onRefresh();
        }
    }
  
    // 此方法计算高度
    private void measureView(View child) {
        ViewGroup.LayoutParams p = child.getLayoutParams();
        if (p == null) {
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
        int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        child.measure(childWidthSpec, childHeightSpec);
    }
  
    public void setAdapter(BaseAdapter adapter) {
        DateFormat format = new SimpleDateFormat("yyyy年MM月dd日  HH:mm");
        String date = format.format(new Date());
        lastUpdatedTime.setText("最近更新:" + date);
        super.setAdapter(adapter);
    }
}
  

layout:
<?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:background="#ffffff" >
  
    <!-- 内容 -->
  
    <RelativeLayout
        android:id="@+id/head_contentLayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="30dip" >
  
        <!-- 箭头图像、进度条 -->
        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true" >
  
            <!-- 箭头 -->
            <ImageView
                android:id="@+id/head_arrowImageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/arrow"
                android:layout_gravity="center" />
              
            <!-- 进度条,style集合了一个anim -->
            <ProgressBar
                android:id="@+id/head_progressBar"
                style="@style/wait_anim"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="gone" />
        </FrameLayout>
          
        <!-- 提示、最近更新 -->
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:gravity="center_horizontal"
            android:orientation="vertical" >
  
            <!-- 提示 -->
            <TextView
                android:id="@+id/head_tipsTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉刷新"
                android:textSize="15dp" />
              
            <!-- 最近更新 -->
            <TextView
                android:id="@+id/head_lastUpdatedTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="上次更新"
                android:textSize="12dp" />
        </LinearLayout>
    </RelativeLayout>
  
</LinearLayout>
  
  
Activity中关键代码:
  
mListView.setonRefreshListener(new OnRefreshListener() {
            public void onRefresh() {
                new AsyncTask<Void, Void, Void>() {
                    protected Void doInBackground(Void... params) {
                        try {
                            Thread.sleep(3000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
//                      dates.addFirst(new AttachmentModule(new Date(), WorkLogContentType.WORKLOG_ATTACHMENT, AttachmentType.Attachment_Nomal));
                        return null;
                    }
  
                    @Override
                    protected void onPostExecute(Void result) {
                        adapter.notifyDataSetChanged();
                        mListView.onRefreshFinished();
                    }
                }.execute(null);
            }
        });