Android之MyRefreshListView上拉加载下拉刷新

仿照SingleLayoutListView.java代码,并完全重写,加上自己的代码风格,优化逻辑,添加了刷新完成头部隐藏动画效果。博客地址:http://blog.csdn.net/yang786654260/article/category/5710631

效果展示

这里写图片描述

MyRefreshListView

使用方法在本节代码后介绍。
代码下载地址:http://download.csdn.net/detail/yang786654260/9024793

package com.example.activity;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.example.logger.Logger;


/** 
 * @author yangshuai
 * @version 创建时间:2015-8-17 上午9:52:51 
 * @类说明 自定义的上拉加载下拉刷新,加载头部或尾部布局之前最好先进行文件配置;
 * @主要配置文件之头部 
 *           {@link #setHeaderNeedRefreshAtFirstShown} 第一次显示时,是否需要刷新;<br>
 *           {@link #setRefreshListener} 设置下拉刷新监听,设置监听后下拉刷新才有效;<br>
 *           {@link #setHeaderResourse} 设置头部资源文件,设置布局前应先配置上面两个;<br>
 * @主要配置文件之尾部
 *           {@link #setFooterAutoLoadMore} 设置是否自动加载更多;<br>
 *           {@link #setLoadMoreListener} 设置上拉加载监听,设置监听后上拉加载才有效;<br>
 *           {@link #onRefreshComplete} 下拉刷新完成;<br>
 *           {@link #setFooterResourse} 设置Footer资源id;<br>
 *           {@link #onLoadMoreComplete} 设置加载完成;<br>
 *           {@link #setFooterNoMoreDataWillBeLoadFlag} 已无更多加载;<br>
 *@头部资源文件要求 头部布局需要有如下几个控件: 箭头ImageView默认向下指向,进度条ProgressBar,信息提示TextView,更新时间TextView
 *@尾部资源文件要求 需要布局文件中有progressbar和TextView两个控件
 */
public class MyRefreshListView extends ListView implements OnScrollListener{

    private Context context;
    private LayoutInflater mInflater;

    /**
     * 判罚是否可以下拉刷新
     */
    private boolean canRefresh = false;

    /**
     * 判罚是否可以上拉加载
     */
    private boolean canLoadMore = false;

    /**
     * 屏幕上第一个item的索引
     */
    private int mFirstItemIndex;

    /**
     * 屏幕上最后一个item索引
     */
    private int mLastItemIndex;

    /**
     * 该listView的总数
     */
    private int mItemCount;

    //================================================== headerView   start ============================================

    private LinearLayout mHeaderView;
    private int headerViewId = -1;
    private int headerArrowImgId;
    private int headerProgressPbId;
    private int headerTipTvId;
    private int headerTimeTvId;
    private ProgressBar headerProgressBar;
    private ImageView headerArrowImg;
    private TextView headerTimeTv;
    private TextView headerTipTv;
    private int mHeaderViewHeight;
    private int mHeaderViewWidth;

    /**
     * 在第一次显示时,是否需要刷新;<\br>
     * if true  会加载一次onRefreshing方法,触发刷新监听
     */
    private boolean headerNeedRefreshAtFirstShown = false;

    /**
     * 在第一次显示时,是否需要刷新;
     * if true  会加载一次onRefreshing方法,触发刷新监听
     * @param headerNeedRefreshAtFirstShown
     */
    public void setHeaderNeedRefreshAtFirstShown( boolean headerNeedRefreshAtFirstShown){
        this.headerNeedRefreshAtFirstShown = headerNeedRefreshAtFirstShown;
    }

    // 下拉刷新的状态标识 start

    /** 松开刷新 */
    private final static int HEADER_RELEASE_TO_REFRESH = 0;

    /** 下拉刷新 */
    private final static int HEADER_PULL_TO_REFRESH = 1;

    /** 正在刷新 */
    private final static int HEADER_REFRESHING = 2;

    /** 刷新完成 or 什么都没做,恢复原状态。 */
    private final static int HEADER_REFRESHED_FINISH = 3;

    // 下拉刷新的状态标识 end

    /**
     * 往下拉时的提示语 
     */
    private String headerPullToRefreshTip = "轻轻下拉,刷新下限";

    /**
     * 释放刷新提示语
     */
    private String headerReleaseToRefreshTip = "哪里的妖怪,快快放开我!";

    /**
     * 正在刷新提示语
     */
    private String headerRefreshingTip = "正在刷新...";

    /**
     * 设置往下拉时的提示语 
     * @param string
     */
    public void setHeaderPullToRefreshString(String string){
        this.headerPullToRefreshTip = string;
    }

    /**
     * 设置释放刷新的提示语 
     * @param string
     */
    public void setHeaderReleaseToRefreshString(String string){
        this.headerReleaseToRefreshTip = string;
    }

    /**
     * 设置释放刷新的提示语 
     * @param string
     */
    public void setHeaderRefreshingString(String string){
        this.headerRefreshingTip = string;
    }

    /**
     * 下拉刷新HeadView的实时状态
     */
    private int mHeadState;

    //箭头动画 start

    /**
     * 箭头旋转动画
     */
    private RotateAnimation headerArrowAnimation;

    /**
     * 箭头还原动画
     */
    private RotateAnimation headerArrowReverseAnimation;

    /**
     * 箭头旋转延时
     */
    private int headerAarrowDuration = 250;

    /**
     * 设置箭头旋转延时
     * @param arrowDuration
     */
    public void setHeaderArrowDuration(int arrowDuration) {
        this.headerAarrowDuration = arrowDuration;
        headerArrowAnimation.setDuration(arrowDuration);
        headerArrowReverseAnimation.setDuration(arrowDuration);
    }

    /**
     * 箭头旋转加速器
     */
    private Interpolator headerArrowInterpolator = new LinearInterpolator();

    /**
     * 设置箭头旋转加速器
     */
    public void setHeaderArrowInterpolator(Interpolator arrowInterpolator) {
        this.headerArrowInterpolator = arrowInterpolator;
        headerArrowAnimation.setInterpolator(arrowInterpolator);
        headerArrowReverseAnimation.setInterpolator(arrowInterpolator);
    }

    //箭头动画  end

    //时间 start

    /**
     * 时间提示语
     */
    private String headerTimeTip = "最近更新时间";

    /**
     * 设置时间提示语
     * @param timeTipString
     */
    public void setHeaderTimeTipString(String timeTipString) {
        this.headerTimeTip = timeTipString;
    }

    /**
     * 时间显示格式
     */
    private String headerTimeDateFormat = "yyyy年MM月dd日 HH:mm";


    /**
     * 设置舌尖显示格式
     * @param timeDateFormat 
     * 举例:"yyyy年MM月dd日 HH:mm"
     */
    public void setHeaderTimeDateFormat(String timeDateFormat) {
        this.headerTimeDateFormat = timeDateFormat;
    }

    //时间 end

    /**
     * 下拉刷新完成后,头部移动动画距离
     */
    private float headerFinishTranslteDistance;

    /**
     * 下拉刷新完成后的提示语
     */
    private String headerRefreshedFinishTip = "下拉刷新成功";

    /**
     * 设置下拉刷新完成后的提示语
     * @param headerRefreshedFinishTip
     */
    public void setHeaderRefreshedFinishTipString(String headerRefreshedFinishTip){
        this.headerRefreshedFinishTip = headerRefreshedFinishTip;
    }

    /**
     * 下拉完成后的移动动画
     */
    private TranslateAnimation translateAnimation;

    /**
     * 头部隐藏动画延迟时间
     */
    private int headerGoBackLocationDelayTime = 200;


    /**
     * 设置头部隐藏动画延迟时间
     * @param headerGoBackLocationDelayTime
     */
    public void setHeaderGoBackLocationDelayTime(int headerGoBackLocationDelayTime){
        this.headerGoBackLocationDelayTime = headerGoBackLocationDelayTime;
    }

    //================================================== headerView   end ==============================================

    //================================================== footerView   start ============================================

    private int footerViewId;
    private int footerProgressId;
    private int footerTipTvId;
    private LinearLayout mFooterView;
    private ProgressBar footerProgressBar;
    private TextView footerTipTv;

    /**
     * 使用自动加载更多
     */
    private boolean footerUseAutoLoadMore = false;

    /**
     * 设置是否自动加载更多
     * @param userAutoLoadMore
     */
    public void setFooterAutoLoadMore(boolean useAutoLoadMore) {
        this.footerUseAutoLoadMore = useAutoLoadMore;
    }

    /**
     * 正在加载更多提示语
     */
    private String footerLoadMoreTip = "正在加载...";

    /**
     * 设置正在加载更多提示语
     */
    public void setFooterLoadMoreString(String loadMoreTip){
        this.footerLoadMoreTip = loadMoreTip;
    }

    /**
     * 加载完成提示语
     */
    private String footerLoadMoreFinishTip = "点击加载完成";

    /**
     * 设置加载完成提示语
     */
    public void setFooterLoadMoreFinishString(String loadMoreFinishTip){
        this.footerLoadMoreFinishTip = loadMoreFinishTip;
    }

    /**
     * 自动加载更多完成提示语
     */
    private String footerAutoLoadMoreFinishTip = "上拉加载更多";

    /**
     * 设置自动加载更多完成提示语
     */
    public void setFooterAutoLoadMoreFinishString(String autoLoadMoreFinishTip){
        this.footerAutoLoadMoreFinishTip = autoLoadMoreFinishTip;
    }

    /**
     * 判断是否可以加载更多
     */
    private boolean footerNoMoreCanLoad = false;

    /**
     * 已无加载更多提示语
     */
    private String footerNoMoreCanLoadTip = "已无更多可加载";

    /**
     * 已无更多提示语显示的持续时间
     */
    private long footerNoMoreTipDelayTime = 3000;

    /**
     * 设置已无更多提示语显示的持续时间
     */
    public void setFooterNoMoreTipDelayTime(long noMoreTipDelayTime){
        this.footerNoMoreTipDelayTime = noMoreTipDelayTime;
    }

    /**
     * 设置已无更多提示语
     * @param noMoreCanLoadString
     */
    public void setFooterNoMoreCanLoadString(String noMoreCanLoadString){
        this.footerNoMoreCanLoadTip = noMoreCanLoadString;
    }

    /**
     * footer状态
     */
    private int mFooterState;

    // 加载更多的状态标识 start

    /** 加载中 */
    public final static int FOOTER_LOADING = 1;

    /** 完成刷新 */
    private final static int FOOTER_LOAD_MORE_FINISH = 2;

    /****** 无更多 *****/
    private final static int FOOTER_NO_MORE_DATA = 3;

    // 加载更多的状态标识 end

    //================================================== footerView    end =============================================

    //==================================================  触摸监听  start  ================================================

    /**
     * 开始触摸的y坐标
     */
    private float mStartY;

    /**
     * 下拉距离比例,到达此比列显示释放刷新界面,跟进查看用法。
     */
    private int RATIO = 3;

    /**
     * 判断上个布局是不是释放刷新
     */
    private boolean HEADER_LAST_VIEW_IS_RELEASE;

    //==================================================  触摸监听  end  ==================================================

    //==================================================   接口 start  ==================================================

    /**
     * 下拉刷新监听
     */
    private MyRefreshListener myRefreshListener = null;

    /**
     * 下拉刷新接口
     * @author yangshuai
     */
    public interface MyRefreshListener{
        public void OnRefreshListener();
    }

    /**
     * 下拉刷新接口监听
     * @param myRefreshListener
     */
    public void setRefreshListener(MyRefreshListener myRefreshListener){
        if (myRefreshListener != null) {
            canRefresh = true;
            this.myRefreshListener = myRefreshListener;
        }
    }

    /**
     * 上拉加载接口监听
     */
    private MyLoadMoreListener myLoadMoreListener = null;

    /**
     * 上拉加载接口
     * @author yangshuai
     */
    public interface MyLoadMoreListener{
        public void OnLoadMore();
    }

    /**
     * 设置上拉加载监听
     * @param myLoadMoreListener
     */
    public void setLoadMoreListener(MyLoadMoreListener myLoadMoreListener){
        canLoadMore = true;
        if (myLoadMoreListener != null) {
            this.myLoadMoreListener = myLoadMoreListener;
        }
    }

    //==================================================   接口 end  ====================================================

    //==================================================   初始化方法 start  ==============================================

    public MyRefreshListView(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public MyRefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public MyRefreshListView(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context){
        this.context = context;
        setCacheColorHint(context.getResources().getColor(android.R.color.transparent));
        setOnLongClickListener(null);
        setOnScrollListener(this);
        mInflater = LayoutInflater.from(context);
    }

    //==================================================   初始化方法 end  ================================================

    //========================================================= headerView相关方法  start==================================

    /**
     * 设置头部资源文件
     * @param headerViewId
     * 头部布局需要有如下几个控件:
     * 箭头ImageView,进度条ProgressBar,信息提示TextView,更新时间TextView
     */
    public void setHeaderResourse(int headerViewId,int arrowImgId,int progressPbId,int tipTvId,int timeTvId){
        this.headerViewId = headerViewId;
        this.headerArrowImgId = arrowImgId;
        this.headerProgressPbId = progressPbId;
        this.headerTipTvId = tipTvId;
        this.headerTimeTvId = timeTvId;
        setHeaderView();
    }

    /**
     * 设置头部布局
     */
    private void setHeaderView() {
        mHeaderView = (LinearLayout) mInflater.inflate(headerViewId, null);
        headerProgressBar = (ProgressBar) mHeaderView.findViewById(headerProgressPbId);
        headerArrowImg = (ImageView) mHeaderView.findViewById(headerArrowImgId);
        headerArrowImg.setMinimumHeight(70);
        headerArrowImg.setMinimumWidth(50);
        headerTimeTv = (TextView) mHeaderView.findViewById(headerTimeTvId);
        headerTipTv = (TextView) mHeaderView.findViewById(headerTipTvId);
        measureView(mHeaderView);
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();
        mHeaderViewWidth = mHeaderView.getMeasuredWidth();
        headerFinishTranslteDistance = -mHeaderViewHeight;
        mHeaderView.setPadding(0, -1 * mHeaderViewHeight, 0, 0);
        mHeaderView.invalidate();
        Toast.makeText(context, "W="+mHeaderViewWidth+"\nH="+mHeaderViewHeight, Toast.LENGTH_LONG).show();
        addHeaderView(mHeaderView, null, false);
        if (headerNeedRefreshAtFirstShown) {
            mHeadState = HEADER_REFRESHING;
            onRefreshing();
        }else {
            mHeadState = HEADER_REFRESHED_FINISH;
        }
        showHeaderViewByState();
        initArrowRotateAnim();
    }

    /**
     * 测量HeadView宽高(注意:此方法仅适用于LinearLayout)
     * @param view
     */
    private void measureView(View view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (params == null) {
            params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        }
        int childeWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        int PHeight = params.height;
        int childeHeightSpec;
        if (PHeight > 0) {
            childeHeightSpec = MeasureSpec.makeMeasureSpec(PHeight, MeasureSpec.EXACTLY);
        }else {
            childeHeightSpec = MeasureSpec.makeMeasureSpec(PHeight, MeasureSpec.UNSPECIFIED);
        }
        view.measure(childeWidthSpec, childeHeightSpec);
    }

    /**
     * 初始化箭头旋转动画
     */
    private void initArrowRotateAnim() {
        headerArrowAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        headerArrowAnimation.setDuration(headerAarrowDuration);
        headerArrowAnimation.setInterpolator(headerArrowInterpolator);
        headerArrowAnimation.setFillAfter(true);
        headerArrowReverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        headerArrowReverseAnimation.setDuration(headerAarrowDuration);
        headerArrowReverseAnimation.setInterpolator(headerArrowInterpolator);
        headerArrowReverseAnimation.setFillAfter(true);
    }

    /**
     * 通过不同的状态改变头部的显示
     */
    private void showHeaderViewByState() {
        switch (mHeadState) {
        case HEADER_RELEASE_TO_REFRESH:
            clearAnimation();
            headerProgressBar.setVisibility(View.GONE);
            headerArrowImg.setVisibility(View.VISIBLE);
            headerArrowImg.clearAnimation();
            headerArrowImg.startAnimation(headerArrowAnimation);
            headerTipTv.setText(headerReleaseToRefreshTip);
            break;
        case HEADER_PULL_TO_REFRESH:
            clearAnimation();
            headerProgressBar.setVisibility(View.GONE);
            headerArrowImg.setVisibility(View.VISIBLE);
            headerArrowImg.clearAnimation();
            setHeaderTipTvText(headerPullToRefreshTip);
            if (HEADER_LAST_VIEW_IS_RELEASE) {
                HEADER_LAST_VIEW_IS_RELEASE = false;
                headerArrowImg.startAnimation(headerArrowReverseAnimation);
            }
            break;
        case HEADER_REFRESHING:
            clearAnimation();
            mHeaderView.setPadding(0, 0, 0, 0);
            headerArrowImg.clearAnimation();
            headerArrowImg.setVisibility(View.GONE);
            headerProgressBar.setVisibility(View.VISIBLE);
            headerTipTv.setText(headerRefreshingTip);
            break;
        case HEADER_REFRESHED_FINISH:
            translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.ABSOLUTE,  headerFinishTranslteDistance);
            translateAnimation.setDuration(headerGoBackLocationDelayTime);
            translateAnimation.setFillAfter(true);
            translateAnimation.setInterpolator(new LinearInterpolator());
            translateAnimation.setAnimationListener(new AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    headerProgressBar.setVisibility(View.GONE);
                    headerArrowImg.setVisibility(View.VISIBLE);
                    headerArrowImg.clearAnimation();
                    headerArrowImg.startAnimation(headerArrowAnimation);
                    setHeaderTipTvText(headerRefreshedFinishTip);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    clearAnimation();
                    mHeaderView.setPadding(0, -1 * mHeaderViewHeight, 0, 0);
                    headerArrowImg.clearAnimation();
                    setHeaderTipTvText(headerPullToRefreshTip);
                }
            });
            startAnimation(translateAnimation);
            break;

        default:
            break;
        }
    }

    /**
     * 设置提示TextView文字
     */
    private void setHeaderTipTvText(String string) {
        headerTipTv.setText(string);
    }

    /**
     * 正在下拉刷新中
     */
    private void onRefreshing(){
        if (myRefreshListener != null) {
            myRefreshListener.OnRefreshListener();
        }
    }

    /**
     * 下拉刷新完成
     */
    public void onRefreshComplete(){

        //在已经无更多加载的情况下,如果下拉刷新的话加载更多可以再启动
        footerNoMoreCanLoad = false;  
        mHeadState = HEADER_REFRESHED_FINISH;
        headerTimeTv.setText(getNewDate());
        showHeaderViewByState();
    }

    /**
     * 下拉刷新逻辑处理
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (!canRefresh || mFirstItemIndex != 0 || mFooterState == FOOTER_LOADING) {
            return super.onTouchEvent(ev);
        }
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartY = ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            float tempY = ev.getY();
            if (mHeadState == HEADER_REFRESHING) {
                break;
            }
            if (mHeadState == HEADER_REFRESHED_FINISH) {
                if (tempY - mStartY > 0) {
                    mHeadState = HEADER_PULL_TO_REFRESH;
                    showHeaderViewByState();
                }
            }
            if (mHeadState == HEADER_PULL_TO_REFRESH) {
                setSelection(0);
                if ((tempY - mStartY)/RATIO >= mHeaderViewHeight) {
                    mHeadState = HEADER_RELEASE_TO_REFRESH;
                    HEADER_LAST_VIEW_IS_RELEASE = true;
                    showHeaderViewByState();
                }else if (tempY - mStartY <= 0) {
                    mHeadState = HEADER_REFRESHED_FINISH;
                    showHeaderViewByState();
                }
                if (mHeadState == HEADER_PULL_TO_REFRESH) {
                    float paddingTop = -1 * mHeaderViewHeight + (tempY - mStartY)/RATIO;
                    Logger.d("paddingTop", ""+(int)paddingTop);
                    mHeaderView.setPadding(0, (int)paddingTop, 0, 0);
                    headerFinishTranslteDistance = -mHeaderViewHeight - paddingTop;
                }
            }
            if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
                setSelection(0);
                if (tempY - mStartY > 0 && (tempY - mStartY)/RATIO < mHeaderViewHeight) {
                    mHeadState = HEADER_PULL_TO_REFRESH;
                    showHeaderViewByState();
                }else if (tempY - mStartY <= 0) {
                    mHeadState = HEADER_REFRESHED_FINISH;
                    showHeaderViewByState();
                }
                if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
                    mHeaderView.setPadding(0, (int)(tempY - mStartY)/RATIO - mHeaderViewHeight, 0, 0);
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            if (mHeadState == HEADER_REFRESHING) {
                break;
            }
            if (mHeadState == HEADER_PULL_TO_REFRESH) {
                mHeadState = HEADER_REFRESHED_FINISH;
                showHeaderViewByState();
            }
            if (mHeadState == HEADER_RELEASE_TO_REFRESH) {
                headerFinishTranslteDistance = -mHeaderViewHeight;
                mHeadState = HEADER_REFRESHING;
                showHeaderViewByState();
                onRefreshing();
            }
            break;

        default:
            break;
        }
        return super.onTouchEvent(ev);
    }
    //========================================================= headerView相关方法  end====================================

    //========================================================= footerView相关方法  start==================================

    /**
     * 设置Footer资源id,需要布局文件中有progressbar和TextView两个控件
     * @param mFooterView    
     * @param mFooterProgress progressBar
     * @param mFooterTipTv  TextView
     */
    public void setFooterResourse(int mFooterView,int mFooterProgress,int mFooterTipTv){
        this.footerViewId = mFooterView;
        this.footerProgressId = mFooterProgress;
        this.footerTipTvId = mFooterTipTv;
        setFooterView();
    }

    /**
     * 设置footer布局
     */
    private void setFooterView(){
        mFooterView = (LinearLayout) mInflater.inflate(footerViewId, null);
        footerProgressBar = (ProgressBar) mFooterView.findViewById(footerProgressId);
        footerTipTv = (TextView) mFooterView.findViewById(footerTipTvId);
        addFooterView(mFooterView);
        mFooterView.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if ( !canLoadMore || canRefresh && mHeadState == HEADER_REFRESHING) {
                    return;
                }
                if (footerNoMoreCanLoad) {
                    return;
                }
                mFooterState = FOOTER_LOADING;
                showFooterViewByState();
                onLoadMore();
            }
        });
        mFooterState = FOOTER_LOAD_MORE_FINISH;
    }

    /**
     * 通过mFooterState改变footer布局显示
     */
    private void showFooterViewByState(){
        switch (mFooterState) {
        case FOOTER_LOADING:
            hideFooterViewHandler.removeMessages(0);
            mFooterView.setVisibility(View.VISIBLE);
            footerProgressBar.setVisibility(View.VISIBLE);
            footerTipTv.setText(footerLoadMoreTip);
            break;
        case FOOTER_LOAD_MORE_FINISH:
            mFooterView.setVisibility(View.VISIBLE);
            footerProgressBar.setVisibility(View.GONE);
            footerTipTv.setText(footerUseAutoLoadMore?footerAutoLoadMoreFinishTip:footerLoadMoreFinishTip);
            hideFooterViewHandler.removeMessages(0);
            hideFooterViewHandler.sendEmptyMessageDelayed(0, footerNoMoreTipDelayTime);
            break;
        case FOOTER_NO_MORE_DATA:
            mFooterView.setVisibility(View.VISIBLE);
            footerProgressBar.setVisibility(View.GONE);
            footerTipTv.setText(footerNoMoreCanLoadTip);
            hideFooterViewHandler.removeMessages(0);
            hideFooterViewHandler.sendEmptyMessageDelayed(0, footerNoMoreTipDelayTime);
            break;
        default:
            break;
        }
    }

    /**
     * 执行上拉加载数据更新
     */
    private void onLoadMore(){
        if (myLoadMoreListener != null) {
            myLoadMoreListener.OnLoadMore();
        }
    }

    /**
     * 设置加载完成
     */
    public void onLoadMoreComplete(){
        mFooterState = FOOTER_LOAD_MORE_FINISH;
        showFooterViewByState();
    }

    /**
     * 延时隐藏footerView
     */
    private Handler hideFooterViewHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {

            mFooterView.setVisibility(View.GONE);
            super.handleMessage(msg);

        }
    };

    /**
     * 已无更多加载
     */
    public void setFooterNoMoreDataWillBeLoadFlag(){
        footerNoMoreCanLoad = true;
        mFooterState = FOOTER_NO_MORE_DATA;
        showFooterViewByState();
    }

    /**
     * 加载更多逻辑处理
     * @param view
     * @param scrollState
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (footerNoMoreCanLoad || mFooterState == FOOTER_LOADING) {
            return;
        }
        if (canLoadMore) {
            if (!(mLastItemIndex == mItemCount && scrollState == SCROLL_STATE_IDLE) || mFooterState == FOOTER_LOADING) {
                return;
            }
            if (canRefresh && mHeadState == HEADER_REFRESHING) {
                mFooterView.setVisibility(View.GONE);
            }else if(footerUseAutoLoadMore){
                mFooterState = FOOTER_LOADING;
                onLoadMore();
                showFooterViewByState();
            }else {
                mFooterState = FOOTER_LOAD_MORE_FINISH;
                showFooterViewByState();
            }
        }else {
            mFooterView.setVisibility(View.GONE);
            this.removeFooterView(mFooterView);
        }
    }

    /**
     * 获取屏幕上第一个和最后一个item的索引
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        mFirstItemIndex = firstVisibleItem;
        mLastItemIndex = firstVisibleItem + visibleItemCount - 2;
        mItemCount = totalItemCount - 2;
    }

    //========================================================= footerView相关方法  end====================================


    /**
     * 设置适配器,加载最开始的刷新时间
     * @param adapter
     */
    public void setAdapter(BaseAdapter adapter) {
        headerTimeTv.setText(getNewDate());
        super.setAdapter(adapter);
    }

    /**
     * 获取最新时间
     * @return
     */
    private String getNewDate() {
        return headerTimeTip+ new SimpleDateFormat(headerTimeDateFormat,Locale.CHINA).format(new Date());
    }

}

使用方法

首先要自定义头部和尾部的布局

头部布局要求:线性布局
头部布局需要有如下几个控件: 箭头ImageView默认向下指向,进度条ProgressBar,信息提示TextView,更新时间TextView。
尾部布局要求:线性布局
需要布局文件中有progressbar和TextView两个控件。

头部示例(这个示例是SingleLayoutListView作者的)
<?xml version="1.0" encoding="utf-8"?>
<!-- ListView的头部 -->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:orientation="horizontal" >

    <!-- 内容 -->

    <RelativeLayout
        android:id="@+id/head_contentLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="8dp"
        android:paddingTop="8dp" >

        <!-- 箭头图像、进度条 -->

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="30dp" >

            <!-- 箭头 -->

            <ImageView
                android:id="@+id/head_arrowImageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:contentDescription="@string/app_name"
                android:src="@drawable/icon_arrow" />

            <!-- 进度条 -->

            <ProgressBar
                android:id="@+id/head_progressBar"
                style="?android:attr/progressBarStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:indeterminateDrawable="@drawable/image_progress"
                android:visibility="gone" />
        </FrameLayout>

        <!-- 提示、最近更新 -->

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="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:textColor="@android:color/black"
                android:textSize="18sp" />

            <!-- 最近更新 -->

            <TextView
                android:id="@+id/head_lastUpdatedTextView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="6dp"
                android:text="更新时间"
                android:textColor="@android:color/black"
                android:textSize="12sp" />
        </LinearLayout>
    </RelativeLayout>

</LinearLayout>
尾部布局示例(这个示例是SingleLayoutListView作者的)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal"
    android:padding="15dp" >

    <ProgressBar
        android:id="@+id/pull_to_refresh_progress"
        style="@android:style/Widget.ProgressBar.Small.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:visibility="gone" >
    </ProgressBar>

    <TextView
        android:id="@+id/load_more"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10.0dp"
        android:gravity="center"
        android:text="加载更多"
        android:textColor="@android:color/black" >
    </TextView>

</LinearLayout>

以上两个布局需要自己实现,实现后通过设置资源id,把id传入listView中:

myRefreshListView.setRefreshListener(new MyRefreshListener() {

            @Override
            public void OnRefreshListener() {
            //下拉刷新监听
            }
        });
myRefreshListView.setLoadMoreListener(new MyLoadMoreListener() {

            @Override
            public void OnLoadMore() {
            //加载更多监听
            }
        });

//在设置布局资源之前要进行需要的配置
myRefreshListView.setHeaderResourse(R.layout.pull_to_refresh_head, R.id.head_arrowImageView, R.id.head_progressBar, R.id.head_tipsTextView, R.id.head_lastUpdatedTextView);
        myRefreshListView.setFooterResourse(R.layout.pull_to_refresh_load_more, R.id.pull_to_refresh_progress, R.id.load_more);

在数据加载完成后调用如下方法,更换布局显示:

//下拉刷新完成
myRefreshListView.onRefreshComplete();

//上拉加载完成
myRefreshListView.onLoadMoreComplete();

//上拉加载数据已无更多
myRefreshListView.setFooterNoMoreDataWillBeLoadFlag();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值