Android自定义上拉加载下拉刷新PullToRefreshListView

  转自http://blog.csdn.net/allen315410/article/details/39965327
  最近项目中要用到刷新和加载的功能,网上查了有好多关于刷新和加载的例子,挑了一个比较好的,有些地方更完善了些。例如下拉不完全时没有做处理,还有加载后滑动有些问题都一一解决了。话不多说,先看效果图,后直接上代码了。
  这里写图片描述
  这里写图片描述
  这里写图片描述
  这里写图片描述
 RefreshListView:

public class RefreshListView extends ListView implements AbsListView.OnScrollListener {

    private final static String TAG = "RefreshListView";
    private View mHeaderView;//头布局对象
    private ImageView mImageViewArror;//头布局的箭头
    private ProgressBar mProgressBar;//进度条
    private TextView mTextViewState;//头布局的状态
    private TextView mTextViewTime;//头布局的时间
    private int mHeaderViewHeight;//mHeaderView的高度
    private Animation mUpAnimation;//顶部的动画
    private Animation mDownAnimation;//底部的动画
    private View mFooterView;//脚布局对象
    private int mFooterViewHeight;//mFooterView的高度
    private boolean mIsScrollToBottom;//是否滑动到底部
    private boolean mIsLoadingMore = false;//是否正在加载更多中
    private OnRefreshListener mOnRefreshListener;
    private int mDownY;//按下时y轴的偏移量
    private final static int DOWM_PULL_REFRESH = 0;//下拉刷新状态
    private final static int RELEASE_REFRESH = 1;//松开刷新
    private final static int REFRESHING = 2;//正在刷新
    private int currentState = DOWM_PULL_REFRESH;//当前布局的状态,默认为下拉刷新状态

    private int mFirstVisibleItemPosition;//屏幕显示在第一个的item的索引

    public RefreshListView(Context context) {
        this(context, null);
    }

    public RefreshListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHeaderView();
        initFooterView();
        this.setOnScrollListener(this);
    }

    /**
     * 初始化头布局
     */
    private void initHeaderView() {
        mHeaderView = View.inflate(getContext(), R.layout.header, null);
        mImageViewArror = (ImageView) mHeaderView.findViewById(R.id.iv_header);
        mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.progressBar);
        mTextViewState = (TextView) mHeaderView.findViewById(R.id.tv_header_state);
        mTextViewTime = (TextView) mHeaderView.findViewById(R.id.tv_header_time);
        //设置最后的刷新时间
        mTextViewTime.setText("最后刷新时间:" + getLastUpdateTime());
        mHeaderView.measure(0, 0);//系统会帮我们测量出mHeaderView的高度
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();
        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
        this.addHeaderView(mHeaderView);//向ListView的顶部添加一个View对象
        initAnimation();
    }

    /**
     * 获取系统最新时间
     *
     * @return
     */
    @TargetApi(Build.VERSION_CODES.N)
    private String getLastUpdateTime() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        return format.format(System.currentTimeMillis());
    }

    /**
     * 初始化动画
     */
    private void initAnimation() {
        mUpAnimation = new RotateAnimation(0f, -180f, Animation.RELATIVE_TO_SELF, 0.5f, Animation
                .RELATIVE_TO_SELF, 0.5f);
        mUpAnimation.setDuration(500);
        mUpAnimation.setFillAfter(true);//动画结束后,停留在结束的位置上
        mDownAnimation = new RotateAnimation(-180f, -360f, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        mDownAnimation.setDuration(500);
        mDownAnimation.setFillAfter(true);
    }

    /**
     * 初始化脚布局
     */
    private void initFooterView() {
        mFooterView = View.inflate(getContext(), R.layout.loading, null);
        mFooterView.measure(0, 0);
        mFooterViewHeight = mFooterView.getMeasuredHeight();
        mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
        this.addFooterView(mFooterView);
    }

    /**
     * 当滚动状态改变时回调
     */
    @Override
    public void onScrollStateChanged(AbsListView absListView, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {
            //判断当前是否已经加载到了底部
            if (mIsScrollToBottom && !mIsLoadingMore) {
                mIsLoadingMore = true;
                //当前到底部
                Log.i(TAG, "加载更多数据");
                mFooterView.setPadding(0, 0, 0, 0);
                this.setSelection(this.getCount());
                if (mOnRefreshListener != null) {
                    mOnRefreshListener.onLoadingMore();
                }
            }
        }
    }

    /**
     * 当滚动时调用
     *
     * @param firstVisibleItem 当前屏幕显示在顶部的item的position
     * @param visibleItemCount 当前屏幕显示了多少个条目的总数
     * @param totalItemCount   ListView的总条目数
     */
    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int
            totalItemCount) {
        mFirstVisibleItemPosition = firstVisibleItem;
        if (getLastVisiblePosition() == (totalItemCount - 1) && !mIsLoadingMore) {
            mIsScrollToBottom = true;
        } else {
            mIsScrollToBottom = false;
        }
    }

    public interface OnRefreshListener {
        /**
         * 下拉刷新
         */
        void onDownPullToRefresh();

        /**
         * 上拉加载更多
         */
        void onLoadingMore();
    }

    /**
     * 设置刷新监听事件
     */
    public void setmOnRefreshListener(OnRefreshListener listener) {
        this.mOnRefreshListener = listener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) ev.getY();
                //移动后的y-按下的y = 间距
                int distanceY = (moveY - mDownY) / 2;
                //-头布局的高度+间距=paddingTop
                int paddingTop = -mHeaderViewHeight + distanceY;
                //如果:- 头布局的高度>paddingTop的值,执行super.onTouchEvent(ev);
                if (mFirstVisibleItemPosition == 0 && -mHeaderViewHeight < paddingTop) {
                    if (paddingTop > 0 && currentState == DOWM_PULL_REFRESH) {//完全显示了
                        Log.i(TAG, "松开刷新");
                        currentState = RELEASE_REFRESH;
                        refreshHeaderView();
                    } else if (paddingTop < 0 && currentState == RELEASE_REFRESH) {
                        Log.i(TAG, "下拉刷新");
                        currentState = DOWM_PULL_REFRESH;
                        refreshHeaderView();
                    }
                    //下拉头布局
                    mHeaderView.setPadding(0, paddingTop, 0, 0);
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                //判断当前状态是松开刷新还是下拉刷新
                switch (currentState) {
                    case RELEASE_REFRESH:
                        Log.i(TAG, "刷新数据");
                        //把头布局设置为完全显示状态
                        mHeaderView.setPadding(0, 0, 0, 0);
                        //进入到正在刷新中状态
                        currentState = REFRESHING;
                        refreshHeaderView();
                        if (mOnRefreshListener != null) {
                            mOnRefreshListener.onDownPullToRefresh();//调用使用者的监听方法
                        }                                                    
                        }
                        break;
                    case DOWM_PULL_REFRESH:
                     //隐藏头布局
                       mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);          
                        break;
                }
                break;
            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 根据currentState刷新头布局
     */
    private void refreshHeaderView() {
        switch (currentState) {
            case DOWM_PULL_REFRESH://下拉刷新
                mTextViewState.setText("下拉刷新");
                mImageViewArror.startAnimation(mDownAnimation);
                break;
            case RELEASE_REFRESH://松开刷新
                mTextViewState.setText("松开刷新");
                mImageViewArror.startAnimation(mUpAnimation);
                break;
            case REFRESHING://正在刷新
                mImageViewArror.clearAnimation();
                mImageViewArror.setVisibility(View.GONE);
                mProgressBar.setVisibility(View.VISIBLE);
                mTextViewState.setText("正在刷新中...");
                break;
        }
    }

    /**
     * 隐藏头布局
     */
    public void hideHeaderView() {
        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
        mImageViewArror.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
        mTextViewState.setText("下拉刷新");
        mTextViewTime.setText("最后刷新时间:" + getLastUpdateTime());
        currentState = DOWM_PULL_REFRESH;
    }

    public void hideFooterView() {
        mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
        mIsLoadingMore = false;
    }
}

MainActivity:

public class MainActivity extends AppCompatActivity implements RefreshListView.OnRefreshListener {

    private RefreshListView mRefreshListView;
    private List<String> mData;
    private MyAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mRefreshListView = (RefreshListView) findViewById(R.id.refresh_listview);
        mData = new ArrayList<>();
        for(int i = 0;i < 25 ; i++){
            mData.add(i,"这是一条listview的数据"+i);
        }
        mAdapter = new MyAdapter(mData,this);
        mRefreshListView.setAdapter(mAdapter);
        mRefreshListView.setmOnRefreshListener(this);
    }

    @Override
    public void onDownPullToRefresh() {
        new AsyncTask<Void,Void,Void>(){

            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    Thread.sleep(2000);
                    for (int i = 0; i < 2;i++) {
                        mData.add(0,"这是下拉刷新出来的数据"+i);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                mAdapter.notifyDataSetChanged();
                mRefreshListView.hideHeaderView();
            }
        }.execute(new Void[]{});
    }

    @Override
    public void onLoadingMore() {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... voids) {
                try {
                    Thread.sleep(3000);
                    mData.add("这是加载的数据1");
                    mData.add("这是加载的数据2");
                    mData.add("这是加载的数据3");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                mAdapter.notifyDataSetChanged();
                //隐藏脚布局
                mRefreshListView.hideFooterView();
            }
        }.execute(new Void[]{});
    }
}

MyAdapter:

public class MyAdapter extends BaseAdapter{

    private List<String> mData;
    private Context mContext;
    private LayoutInflater mInflater;

    public MyAdapter(List<String> mData, Context mContext) {
        if(mData == null){
            this.mData = mData;
        }
        this.mData = mData;
        this.mContext = mContext;
        mInflater = LayoutInflater.from(mContext);
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int i) {
        return mData.get(i);
    }

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

    @Override
    public View getView(int i, View convertView, ViewGroup viewGroup) {
        ViewHolder holder;
        if(convertView == null){
            convertView = mInflater.inflate(R.layout.listview_item,viewGroup,false);
            holder = new ViewHolder();
            convertView.setTag(holder);
            holder.tvItem = (TextView) convertView.findViewById(R.id.tv_item);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.tvItem.setText(mData.get(i));
        return convertView;
    }

    private class ViewHolder {
        private TextView tvItem;
    }
}

activity_main的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ihavau.www.pulltorefreshlistviewdemo.MainActivity">

        <com.ihavau.www.pulltorefreshlistviewdemo.widget.RefreshListView
            android:id="@+id/refresh_listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</RelativeLayout>

header.xml的布局:

<?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="wrap_content"
              android:orientation="horizontal">

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp">

        <ImageView
            android:id="@+id/iv_header"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:minHeight="30dp"
            android:src="@drawable/ptr_pulltorefresh_arrow"/>

        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@anim/common_progressbar"
            android:visibility="gone"/>
    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_header_state"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉刷新"
            android:textColor="#FF0000"
            android:textSize="18sp"/>

        <TextView
            android:id="@+id/tv_header_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:text="最后刷新时间:2016-6-7 17:47:30"/>
    </LinearLayout>
</LinearLayout>

footer的布局:

<?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="wrap_content"
              android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_margin="10dp"
        android:gravity="center"
        android:orientation="horizontal">

        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:indeterminateDrawable="@anim/common_progressbar"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="加载更多..."
            android:textColor="#FF0000"
            android:textSize="18sp"/>
    </LinearLayout>
</LinearLayout>

listview_item.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">

    <TextView
        android:id="@+id/tv_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:textSize="18sp"/>

</LinearLayout>

代码下载地址:http://download.csdn.net/detail/zuozuoshenghen/9593649

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值