ListView的下拉刷新和上拉加载

来源:互联网 发布:php源码 虚拟股票 编辑:程序博客网 时间:2024/05/24 01:40

我们公司以前有道面试题,让开发人员当场写一个ListView的下拉刷新和上拉加载,时间2个小时左右,允许有微量Bug。

自己想一想,也不知道能不能写的出来,所以今天有时间,参考了网上的一些资料,先写一个练手下。先看下效果图:

这里写图片描述这里写图片描述

实现原理

ListView有一个addHeaderView()和addFooterView()方法,就是添加一个头布局和一个脚布局。主要通过这两个方法来实现。

初始化的时候,添加头布局和脚布局。然后把头布局的paddingTop设置为负的头布局高度,这样头布局就会看不见了。脚布局同样处理。

在手指滑动的时候,不断的去改变paddingTop的值,这样,就形成下拉的效果了。

注意:对于ListView判断滑动到顶部和底部的监听

ListView自带一个setOnScrollListener()监听器,主要用来监听它的滑动时间的。

@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {    switch (scrollState) {        case OnScrollListener.SCROLL_STATE_IDLE:            //空闲状态,停止滚动            break;        case OnScrollListener.SCROLL_STATE_FLING:            // 手指快速滚动            break;        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:            // 正在滚动            break;    }}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}

调用方法

  • 直接引用PullToRefreshListView类到你的工程,copy布局文件。
  • 由于下拉刷新的头布局和上拉加载的布局是固定的,没有提供接口动态加载。所有如果要引用的话,得去修改xml文件。
  • 可以禁止下拉刷新或者上拉加载,通过setNeedPullToRefresh()和setNeedLoadMore()方法。
  • 每次刷新完毕,请调用refreshComplete()方法。
  • setOnRefreshListener()设置下拉和上拉的监听回调。
package com.geek.widget;import java.text.SimpleDateFormat;import java.util.Locale;import com.zhou.customviewone.R;import android.annotation.SuppressLint;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ImageView;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;/** *  * 下拉刷新和上拉加载的ListView *  * @author LeeShenzhou * */public class PullToRefreshListView extends ListView implements OnScrollListener {    // 头布局    private View mHeaderView;    private ImageView mImageArrow;    private ProgressBar mProgressBar;    private TextView mTxtState;    private TextView mTxtUpdateTime;    // 脚布局    private View mFooterView;    // 头布局的高度    private int headerHeight;    // 脚布局的高度    private int footerHeight;    private int mDownY;    // 下拉刷新    private final int DOWN_REFRESH = 0;    // 松开刷新    private final int RELEASE_REFRESH = 1;    // 正在刷新中    private final int REFRESHING = 2;    private int currentState = DOWN_REFRESH;    private boolean isLoadMore;    // 是否需要下拉刷新    private boolean isNeedPullToRefresh;    // 是否需要上拉加载更多    private boolean isNeedLoadMore;    /**     * 是否需要下拉刷新     */    public void setNeedPullToRefresh(boolean need) {        this.isNeedPullToRefresh = need;    }    /**     * 是否需要上拉加载更多     */    public void setNeedLoadMore(boolean need) {        this.isNeedLoadMore = need;    }    /**     * 刷新完成     */    public void refreshComplete() {        isLoadMore = false;        currentState = DOWN_REFRESH;        mHeaderView.setPadding(0, -headerHeight, 0, 0);        mFooterView.setPadding(0, -footerHeight, 0, 0);    }    private OnRefreshListener listener;    public void setOnRefreshListener(OnRefreshListener listener) {        this.listener = listener;    }    public PullToRefreshListView(Context context) {        super(context);        init();    }    public PullToRefreshListView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        init();    }    private void init() {        isNeedLoadMore = true;        isNeedPullToRefresh = true;        isLoadMore = false;        // 初始化头布局        mHeaderView = View.inflate(getContext(), R.layout.layout_pull_to_refresh_header, null);        mImageArrow = (ImageView) mHeaderView.findViewById(R.id.header_image_arrow);        mProgressBar = (ProgressBar) mHeaderView.findViewById(R.id.header_pb);        mTxtState = (TextView) mHeaderView.findViewById(R.id.header_state);        mTxtUpdateTime = (TextView) mHeaderView.findViewById(R.id.header_update_time);        mHeaderView.measure(0, 0); // 系统会帮我们测量出HeaderView的高度        headerHeight = mHeaderView.getMeasuredHeight();        mHeaderView.setPadding(0, -headerHeight, 0, 0);        addHeaderView(mHeaderView);        // 初始化脚布局        mFooterView = View.inflate(getContext(), R.layout.layout_pull_to_refresh_footer, null);        mFooterView.measure(0, 0);        footerHeight = mFooterView.getMeasuredHeight();        mFooterView.setPadding(0, -footerHeight, 0, 0);        addFooterView(mFooterView);        // 设置最后刷新时间        setLastUpdateTime();        setOnScrollListener(this);    }    private void setLastUpdateTime() {        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());        String time = sdf.format(System.currentTimeMillis());        if (mTxtUpdateTime != null) {            mTxtUpdateTime.setText("最新更新: " + time);        }    }    @SuppressLint("ClickableViewAccessibility")    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (!isNeedPullToRefresh) {            return super.onTouchEvent(ev);        }        switch (ev.getAction()) {        case MotionEvent.ACTION_DOWN:            mDownY = (int) ev.getY();            break;        case MotionEvent.ACTION_MOVE:            int moveY = (int) ev.getY();            final int offset = (moveY - mDownY) / 2;            int paddingTop = -headerHeight + offset;            if (getFirstVisiblePosition() == 0 && paddingTop > -headerHeight) {                if (currentState != REFRESHING) {                    if (offset > headerHeight && currentState == DOWN_REFRESH) {                        // 完全显示了                        currentState = RELEASE_REFRESH;                        changeHeaderView();                    } else if (offset < headerHeight && currentState == RELEASE_REFRESH) {                        // 没有显示完全                        currentState = DOWN_REFRESH;                        changeHeaderView();                    }                }                if (currentState == REFRESHING) {                    mHeaderView.setPadding(0, offset, 0, 0);                } else {                    mHeaderView.setPadding(0, paddingTop, 0, 0);                }            }            break;        case MotionEvent.ACTION_UP:            if (currentState == REFRESHING) {                mHeaderView.setPadding(0, 0, 0, 0);                setSelection(0);                return super.onTouchEvent(ev);            }            // 判断当前的状态是松开刷新还是下拉刷新            if (currentState == RELEASE_REFRESH) {                mHeaderView.setPadding(0, 0, 0, 0);                currentState = REFRESHING;                changeHeaderView();                setSelection(0);                if (listener != null) {                    listener.onPullToRefresh();                }            } else if (currentState == DOWN_REFRESH) {                mHeaderView.setPadding(0, -headerHeight, 0, 0);            }            break;        default:            break;        }        return super.onTouchEvent(ev);    }    private void changeHeaderView() {        switch (currentState) {        case DOWN_REFRESH:            // 下拉刷新            mTxtState.setText("下拉刷新");            mProgressBar.setVisibility(View.GONE);            mImageArrow.setVisibility(View.VISIBLE);            mImageArrow.setImageResource(R.drawable.arrow_down);            break;        case RELEASE_REFRESH:            // 松开刷新            mTxtState.setText("释放立即刷新");            mProgressBar.setVisibility(View.GONE);            mImageArrow.setVisibility(View.VISIBLE);            mImageArrow.setImageResource(R.drawable.arrow_pull);            break;        case REFRESHING:            // 正在刷新            mImageArrow.setVisibility(View.GONE);            mProgressBar.setVisibility(View.VISIBLE);            mTxtState.setText("正在刷新...");            break;        default:            break;        }    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        if (!isNeedLoadMore || isLoadMore) {            return;        }        if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_FLING) {            // 判断当前是否已经到了底部            if (getLastVisiblePosition() == (getCount() - 1)) {                isLoadMore = true;                mFooterView.setPadding(0, 0, 0, 0);                setSelection(getCount());                if (listener != null) {                    listener.onLoadMore();                }            }        }    }    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        if (firstVisibleItem != 0) {            // 重置刷新状态            if (currentState != REFRESHING) {                currentState = DOWN_REFRESH;            }        }    }    public interface OnRefreshListener {        /**         * 下拉刷新         */        void onPullToRefresh();        /**         * 上拉加载更多         */        void onLoadMore();    }}

源码下载:https://git.oschina.net/nszKnife/AndroidView

0 0
原创粉丝点击