自定义ListView的下拉刷新和上拉加载更多

来源:互联网 发布:centos指令大全 编辑:程序博客网 时间:2024/05/13 17:26
/** * Created by Ext on 2016/8/5. */public class LoadMoreListView extends ListView implements AbsListView.OnScrollListener {    private View mFooter;    private View mHeader;    private int mHeaderHeight;    private int totalItemCount;    private int lastVisibleItem; // 最后一个可见的item    private int firstVisibleItem;    private boolean isRemark; // 标记,当前是否在listView最顶端按下    private int startY; // 按下时的Y    private int state; // 当前的状态    private final int NONE = 0; // 正常状态    private final int PULL = 1; // 提示下拉状态    private final int RELEASE = 2; // 提示释放状态    private final int REFRESHING = 3; // 刷新状态    private int scrollState; // 当前滚动状态    private TextView tipTv;    private ImageView arrowIv;    private ProgressBar progressBar;    private TextView updateTimeTv;    private boolean isLoading;    private ILoadMoreListener mLoadMoreListener;    private RotateAnimation animDown;    private RotateAnimation animUp;    private View mLoadingLayout;    public LoadMoreListView(Context context) {        this(context, null);    }    public LoadMoreListView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public LoadMoreListView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context);    }    /**     * 添加底部加载提示布局到ListView     * @param context     */    private void initView(Context context) {        LayoutInflater inflater = LayoutInflater.from(context);        mFooter = inflater.inflate(R.layout.footer_layout, null);        mLoadingLayout = mFooter.findViewById(R.id.load_layout);        mLoadingLayout.setVisibility(View.GONE);        this.addFooterView(mFooter);        mHeader = inflater.inflate(R.layout.header_layout, null);        measureView(mHeader);        mHeaderHeight = mHeader.getMeasuredHeight();        topPadding(-mHeaderHeight);        this.addHeaderView(mHeader);        this.setOnScrollListener(this);    }    /**     * 通知父布局,占用的宽、高     * @param view     */    private void measureView(View view) {        ViewGroup.LayoutParams p = view.getLayoutParams();        if (p == null) {            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);        }        // 宽度测量规格        int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);        // 高度测量规格        int height;        int tempHeight = p.height;        if (tempHeight > 0) {            height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);        } else {            height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);        }        view.measure(width, height);    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        switch (ev.getActionMasked()) {            case MotionEvent.ACTION_DOWN:                if (firstVisibleItem == 0) {                    isRemark = true;                    startY = (int) ev.getY();                }                break;            case MotionEvent.ACTION_MOVE:                onMove(ev);                break;            case MotionEvent.ACTION_UP:                // 松手后头布局处于两种状态                if (state == RELEASE) {                    state = REFRESHING;                    refreshViewByState();                    // 加载数据                    if (mLoadMoreListener != null) {                        mLoadMoreListener.onRefresh();                    }                } else if (state == PULL) {                    state = NONE;                    isRemark = false;                    refreshViewByState();                }                break;        }        return super.onTouchEvent(ev);    }    /**     * 判断移动过程操作     * @param ev     */    private void onMove(MotionEvent ev){        if (!isRemark) {            return;        }        int tempY = (int)ev.getY();        // space 摁下后滑动的垂直距离        int space = tempY - startY;        int topPadding = space - mHeaderHeight;        if (topPadding > mHeaderHeight + 20) {            topPadding = mHeaderHeight + 20;        }        switch (state) {            case NONE:                if (space > 0) {                    state = PULL;                    refreshViewByState();                }                break;            case PULL:                // 滑动距离大于一定高度之后就更新状态                topPadding(topPadding);                if (space > mHeaderHeight + 10 && scrollState == SCROLL_STATE_TOUCH_SCROLL) {                    state = RELEASE;                    refreshViewByState();                }                break;            case RELEASE:                // 限制头部布局的topPadding                if (topPadding >= mHeaderHeight + 20) {                    topPadding = mHeaderHeight;                }                topPadding(topPadding);                if (space < mHeaderHeight + 10) {                    state = PULL;                    refreshViewByState();                } else if (space <= 0) {                    state = NONE;                    isRemark = false;                    refreshViewByState();                }                break;            case REFRESHING:                break;        }    }    /**     * 根据当前状态,改变界面显示(只要在滑动时状态变化就需要调用)     */    private void refreshViewByState() {        if (tipTv == null) {            tipTv = (TextView) mHeader.findViewById(R.id.tip_tv);        }        if (arrowIv == null) {            arrowIv = (ImageView) mHeader.findViewById(R.id.arrow);        }        if (progressBar == null) {            progressBar = (ProgressBar) mHeader.findViewById(R.id.progress);        }        if (animDown == null) {            animDown = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);            animDown.setDuration(500);            animDown.setFillAfter(true);        }        if (animUp == null) {            animUp = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);            animUp.setDuration(500);            animUp.setFillAfter(true);        }        switch (state) {            case NONE:                topPadding(-mHeaderHeight);                break;            case PULL:                arrowIv.setVisibility(VISIBLE);                progressBar.setVisibility(GONE);                tipTv.setText("下拉可以刷新");                arrowIv.clearAnimation();                arrowIv.setAnimation(animDown);                break;            case RELEASE:                arrowIv.setVisibility(VISIBLE);                progressBar.setVisibility(GONE);                tipTv.setText("松开可以刷新");                arrowIv.clearAnimation();                arrowIv.setAnimation(animUp);                break;            case REFRESHING:                topPadding(10);                arrowIv.setVisibility(GONE);                progressBar.setVisibility(VISIBLE);                tipTv.setText("正在刷新");                arrowIv.clearAnimation();                break;        }    }    /**     * 加载完更多数据     */    public void loadComplete() {        isLoading = false;        mLoadingLayout.setVisibility(View.GONE);        invalidate();    }    /**     * 获取完数据     */    public void refreshComplete() {        state = NONE;        isRemark = false;        refreshViewByState();        if (updateTimeTv == null) {            updateTimeTv = (TextView) mHeader.findViewById(R.id.time_tv);        }        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd hh:mm:ss");        Date date = new Date(System.currentTimeMillis());        updateTimeTv.setText(format.format(date));    }    @Override    public void onScrollStateChanged(AbsListView view, int scrollState) {        // 针对加载更多        if (totalItemCount == lastVisibleItem && scrollState == SCROLL_STATE_IDLE) {            if (!isLoading) {                isLoading = true;                mLoadingLayout.setVisibility(View.VISIBLE);                if (mLoadMoreListener != null) {                    mLoadMoreListener.onLoadMore();                }            }        }        // 针对下拉刷新        this.scrollState = scrollState;    }    /**     *     * @param view     * @param firstVisibleItem 第一个可见的item的数据在数据集中的索引     * @param visibleItemCount 当前屏幕可见的item总数     * @param totalItemCount 数据集中数据的总数     */    @Override    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {        this.firstVisibleItem = firstVisibleItem;        this.lastVisibleItem = firstVisibleItem + visibleItemCount;        this.totalItemCount = totalItemCount;    }    private void topPadding(int topPadding) {        mHeader.setPadding(mHeader.getPaddingLeft(), topPadding, mHeader.getPaddingRight(), mHeader.getPaddingBottom());    }    public void setLoadMoreListener(ILoadMoreListener mLoadMoreListener) {        this.mLoadMoreListener = mLoadMoreListener;    }    public interface ILoadMoreListener {        public void onLoadMore();        public void onRefresh();    }}
0 0