Android 下拉刷新和上拉加载

有一个比较好用的这个自定义view,方便以后直接使用,我记得是在GitHub上down下来的,我找不到地址了,所以直接粘贴,原作者发现告诉我地址,我注明

package com.example.orion.htmltext1.View;

import android.view.View;

/**
 * 当前类注释:
 * 作者:jinwenfeng on 2016/12/6 13:48
 * 邮箱:[email protected]
 * QQ823546371
 * 公司:南京穆尊信息科技有限公司
 * © 2016 jinwenfeng
 * © 版权所有,未经允许不得传播
 */
public interface FooterView {

    /**
     * 开始下拉
     */
    void begin();

    /**
     * 回调的精度,单位为px
     *
     * @param progress 当前高度
     * @param all      总高度   为默认高度的2     */
    void progress(float progress, float all);

    void finishing(float progress, float all);
    /**
     * 下拉完毕
     */
    void loading();

    /**
     * 看不见的状态
     */
    void normal();

    /**
     * 返回当前视图
     * */
    View getView();

}
package com.example.orion.htmltext1.View;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.orion.htmltext1.R;


/**
 * 当前类注释:
 * 作者:jinwenfeng on 2016/12/6 13:49
 * 邮箱:[email protected]
 * QQ823546371
 * 公司:南京穆尊信息科技有限公司
 * © 2016 jinwenfeng
 * © 版权所有,未经允许不得传播
 */
public class HeadRefreshView extends FrameLayout implements HeadView {

    private TextView tv;
    private ImageView arrow;
    private ProgressBar progressBar;

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

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

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

    private void init(Context context) {
        View view = LayoutInflater.from(context).inflate(R.layout.layout_header,null);
        addView(view);
        tv = (TextView) view.findViewById(R.id.header_tv);
        arrow = (ImageView) view.findViewById(R.id.header_arrow);
        progressBar = (ProgressBar) view.findViewById(R.id.header_progress);
    }

    @Override
    public void begin() {

    }

    @Override
    public void progress(float progress, float all) {
        float s = progress / all;
        if (s >= 0.9f){
            arrow.setRotation(180);
        }else{
            arrow.setRotation(0);
        }
        if (progress >= all-10){
            tv.setText("松开刷新");
        }else{
            tv.setText("下拉加载");
        }
    }

    @Override
    public void finishing(float progress, float all) {

    }

    @Override
    public void loading() {
        arrow.setVisibility(GONE);
        progressBar.setVisibility(VISIBLE);
        tv.setText("刷新中...");
    }

    @Override
    public void normal() {
        arrow.setVisibility(VISIBLE);
        progressBar.setVisibility(GONE);
        tv.setText("下拉刷新");
    }

    @Override
    public View getView() {
        return this;
    }
}
package com.example.orion.htmltext1.View;

import android.view.View;

/**
 * 当前类注释:
 * 作者:jinwenfeng on 2016/12/6 13:48
 * 邮箱:[email protected]
 * QQ823546371
 * 公司:南京穆尊信息科技有限公司
 * © 2016 jinwenfeng
 * © 版权所有,未经允许不得传播
 */
public interface HeadView {

    /**
     * 开始下拉
     */
    void begin();

    /**
     * 回调的精度,单位为px
     *
     * @param progress 当前高度
     * @param all      总高度
     */
    void progress(float progress, float all);

    void finishing(float progress, float all);
    /**
     * 下拉完毕
     */
    void loading();

    /**
     * 看不见的状态
     */
    void normal();

    /**
     * 返回当前视图
     * */
    View getView();

}
package com.example.orion.htmltext1.View;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.orion.htmltext1.R;


/**
 * 当前类注释:
 * 作者:jinwenfeng on 2016/12/8 10:47
 * 邮箱:[email protected]
 * QQ823546371
 * 公司:南京穆尊信息科技有限公司
 * © 2016 jinwenfeng
 * © 版权所有,未经允许不得传播
 */
public class LoadMoreView extends FrameLayout implements FooterView {

    private TextView tv;
    private ImageView arrow;
    private ProgressBar progressBar;

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

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

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

    private void init(Context context) {
        View view = LayoutInflater.from(context).inflate(R.layout.layout_header,null);
        addView(view);
        tv = (TextView) view.findViewById(R.id.header_tv);
        arrow = (ImageView) view.findViewById(R.id.header_arrow);
        progressBar = (ProgressBar) view.findViewById(R.id.header_progress);
    }

    @Override
    public void begin() {

    }

    @Override
    public void progress(float progress, float all) {
        float s = progress / all;
        if (s >= 0.9f){
            arrow.setRotation(0);
        }else{
            arrow.setRotation(180);
        }
        if (progress >= all-10){
            tv.setText("松开加载更多");
        }else{
            tv.setText("上拉加载");
        }
    }

    @Override
    public void finishing(float progress, float all) {

    }

    @Override
    public void loading() {
        arrow.setVisibility(GONE);
        progressBar.setVisibility(VISIBLE);
        tv.setText("加载中...");
    }

    @Override
    public void normal() {
        arrow.setVisibility(VISIBLE);
        progressBar.setVisibility(GONE);
        tv.setText("上拉加载");
    }

    @Override
    public View getView() {
        return this;
    }
}
package com.example.orion.htmltext1.View;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import com.example.orion.htmltext1.R;
import com.example.orion.htmltext1.Util.DisplayUtil;
import com.example.orion.htmltext1.interfaces.BaseRefreshListener;
import com.example.orion.htmltext1.interfaces.State;
import com.example.orion.htmltext1.interfaces.ViewStatus;

/**
 * 当前类注释:
 * 作者:jinwenfeng on 2016/12/6 11:52
 * 邮箱:[email protected]
 * QQ823546371
 * 公司:南京穆尊信息科技有限公司
 * © 2016 jinwenfeng
 * © 版权所有,未经允许不得传播
 */
public class PullToRefreshLayout extends FrameLayout {

    private HeadView mHeaderView;
    private FooterView mFooterView;
    private View mChildView;

    private static final long ANIM_TIME = 300;
    private static int HEAD_HEIGHT = 60;
    private static int FOOT_HEIGHT = 60;

    private static int head_height;
    private static int head_height_2;
    private static int foot_height;
    private static int foot_height_2;

    private float mTouchY;
    private float mCurrentY;

    private boolean canLoadMore = true;
    private boolean canRefresh = true;
    private boolean isRefresh;
    private boolean isLoadMore;

    //滑动的最小距离
    private int mTouchSlope;

    private BaseRefreshListener refreshListener;


    private View loadingView, errorView, emptyView;
    private int loading = R.layout.layout_loading, empty = R.layout.layout_empty, error = R.layout.layout_error;

    public void setRefreshListener(BaseRefreshListener refreshListener) {
        this.refreshListener = refreshListener;
    }

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

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

    public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullToRefreshLayout, defStyleAttr, 0);
        error = a.getResourceId(R.styleable.PullToRefreshLayout_view_error, error);
        loading = a.getResourceId(R.styleable.PullToRefreshLayout_view_loading, loading);
        empty = a.getResourceId(R.styleable.PullToRefreshLayout_view_empty, empty);

        init();
    }

    private void cal() {
        head_height = DisplayUtil.dp2Px(getContext(), HEAD_HEIGHT);
        foot_height = DisplayUtil.dp2Px(getContext(), FOOT_HEIGHT);
        head_height_2 = DisplayUtil.dp2Px(getContext(), HEAD_HEIGHT * 2);
        foot_height_2 = DisplayUtil.dp2Px(getContext(), FOOT_HEIGHT * 2);

        mTouchSlope = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    }

    private void init() {
        cal();
        int count = getChildCount();
        if (count != 1) {
            new IllegalArgumentException("child only can be one");
        }

    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mChildView = getChildAt(0);
        addHeadView();
        addFooterView();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

    }

    private void addHeadView() {
        if (mHeaderView == null) {
            mHeaderView = new HeadRefreshView(getContext());
        }else{
            removeView(mHeaderView.getView());
        }
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
        mHeaderView.getView().setLayoutParams(layoutParams);
        if (mHeaderView.getView().getParent() != null)
            ((ViewGroup) mHeaderView.getView().getParent()).removeAllViews();
        addView(mHeaderView.getView(), 0);
    }

    private void addFooterView() {
        if (mFooterView == null) {
            mFooterView = new LoadMoreView(getContext());
        }else{
            removeView(mFooterView.getView());
        }
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
        layoutParams.gravity = Gravity.BOTTOM;
        mFooterView.getView().setLayoutParams(layoutParams);
        if (mFooterView.getView().getParent() != null)
            ((ViewGroup) mFooterView.getView().getParent()).removeAllViews();
        addView(mFooterView.getView());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (!canLoadMore && !canRefresh) return super.onInterceptTouchEvent(ev);
        //if (isRefresh || isLoadMore) return true;
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mTouchY = ev.getY();
                mCurrentY = mTouchY;
                break;
            case MotionEvent.ACTION_MOVE:
                float currentY = ev.getY();
                float dy = currentY - mCurrentY;
                if (canRefresh) {
                    boolean canChildScrollUp = canChildScrollUp();
                    if (dy > mTouchSlope && !canChildScrollUp) {
                        mHeaderView.begin();
                        return true;
                    }
                }
                if (canLoadMore) {
                    boolean canChildScrollDown = canChildScrollDown();
                    if (dy < -mTouchSlope && !canChildScrollDown) {
                        mFooterView.begin();
                        return true;
                    }
                }
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isRefresh || isLoadMore) return true;
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                mCurrentY = event.getY();
                float dura = (mCurrentY - mTouchY) / 3.0f;
                if (dura > 0 && canRefresh) {
                    dura = Math.min(head_height_2, dura);
                    dura = Math.max(0, dura);
                    mHeaderView.getView().getLayoutParams().height = (int) dura;
                    ViewCompat.setTranslationY(mChildView, dura);
                    requestLayout();
                    mHeaderView.progress(dura, head_height);
                } else {
                    if (canLoadMore) {
                        dura = Math.min(foot_height_2, Math.abs(dura));
                        dura = Math.max(0, Math.abs(dura));
                        mFooterView.getView().getLayoutParams().height = (int) dura;
                        ViewCompat.setTranslationY(mChildView, -dura);
                        requestLayout();
                        mFooterView.progress(dura, foot_height);
                    }
                }
                return true;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                float currentY = event.getY();
                final int dy1 = (int) (currentY - mTouchY) / 3;
                if (dy1 > 0 && canRefresh) {
                    if (dy1 >= head_height) {
                        createAnimatorTranslationY(State.REFRESH,
                                dy1 > head_height_2 ? head_height_2 : dy1, head_height,
                                new CallBack() {
                                    @Override
                                    public void onSuccess() {
                                        isRefresh = true;
                                        if (refreshListener != null) {
                                            refreshListener.refresh();
                                        }
                                        mHeaderView.loading();
                                    }
                                });
                    } else if (dy1 > 0 && dy1 < head_height) {
                        setFinish(dy1, State.REFRESH);
                        mHeaderView.normal();
                    }
                } else {
                    if (canLoadMore) {
                        if (Math.abs(dy1) >= foot_height) {
                            createAnimatorTranslationY(State.LOADMORE, Math.abs(dy1) > foot_height_2 ? foot_height_2 : Math.abs(dy1), foot_height, new CallBack() {
                                @Override
                                public void onSuccess() {
                                    isLoadMore = true;
                                    if (refreshListener != null) {
                                        refreshListener.loadMore();
                                    }
                                    mFooterView.loading();
                                }
                            });
                        } else {
                            setFinish(Math.abs(dy1), State.LOADMORE);
                            mFooterView.normal();
                        }
                    }
                }
                break;
        }
        return super.onTouchEvent(event);
    }

    private boolean canChildScrollDown() {
        if (mChildView == null) {
            return false;
        }
        return ViewCompat.canScrollVertically(mChildView, 1);
    }

    private boolean canChildScrollUp() {
        if (mChildView == null) {
            return false;
        }
        return ViewCompat.canScrollVertically(mChildView, -1);
    }

    /**
     * 创建动画
     */
    public void createAnimatorTranslationY(@State.REFRESH_STATE final int state, final int start,
                                           final int purpose, final CallBack callBack) {
        final ValueAnimator anim;
        anim = ValueAnimator.ofInt(start, purpose);
        anim.setDuration(ANIM_TIME);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                int value = (int) valueAnimator.getAnimatedValue();
                if (state == State.REFRESH) {
                    mHeaderView.getView().getLayoutParams().height = value;
                    ViewCompat.setTranslationY(mChildView, value);
                    if (purpose == 0) { //代表结束加载
                        mHeaderView.finishing(value, head_height_2);
                    } else {
                        mHeaderView.progress(value, head_height);
                    }
                } else {
                    mFooterView.getView().getLayoutParams().height = value;
                    ViewCompat.setTranslationY(mChildView, -value);
                    if (purpose == 0) { //代表结束加载
                        mFooterView.finishing(value, head_height_2);
                    } else {
                        mFooterView.progress(value, foot_height);
                    }
                }
                if (value == purpose) {
                    if (callBack != null)
                        callBack.onSuccess();
                }
                requestLayout();


            }

        });
        anim.start();
    }

    /**
     * 结束下拉刷新
     */
    private void setFinish(int height, @State.REFRESH_STATE final int state) {
        createAnimatorTranslationY(state, height, 0, new CallBack() {
            @Override
            public void onSuccess() {
                if (state == State.REFRESH) {
                    isRefresh = false;
                    mHeaderView.normal();

                } else {
                    isLoadMore = false;
                    mFooterView.normal();
                }
            }
        });
    }

    private void setFinish(@State.REFRESH_STATE int state) {
        if (state == State.REFRESH) {
            if (mHeaderView != null && mHeaderView.getView().getLayoutParams().height > 0 && isRefresh) {
                setFinish(head_height, state);
            }
        } else {
            if (mFooterView != null && mFooterView.getView().getLayoutParams().height > 0 && isLoadMore) {
                setFinish(foot_height, state);
            }
        }
    }

    public interface CallBack {
        void onSuccess();
    }

    private void showLoadingView() {
        if (loadingView == null) {
            loadingView = LayoutInflater.from(getContext()).inflate(loading, null);
            LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            addView(loadingView, layoutParams);
        } else {
            loadingView.setVisibility(VISIBLE);
        }
    }

    private void showEmptyView() {
        if (emptyView == null) {
            emptyView = LayoutInflater.from(getContext()).inflate(empty, null);
            LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            addView(emptyView, layoutParams);
        } else {
            emptyView.setVisibility(VISIBLE);
        }
    }

    private void showErrorView() {
        if (errorView == null) {
            errorView = LayoutInflater.from(getContext()).inflate(error, null);
            LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            addView(errorView, layoutParams);
        } else {
            errorView.setVisibility(VISIBLE);
        }
    }

    private void hideView(View view) {
        if (view != null)
            view.setVisibility(GONE);
    }

    private void switchView(int status) {
        switch (status) {
            case ViewStatus.CONTENT_STATUS:
                hideView(loadingView);
                hideView(emptyView);
                hideView(errorView);

                mChildView.setVisibility(VISIBLE);
                break;
            case ViewStatus.LOADING_STATUS:
                hideView(mChildView);
                hideView(emptyView);
                hideView(errorView);

                showLoadingView();
                break;
            case ViewStatus.EMPTY_STATUS:
                hideView(mChildView);
                hideView(loadingView);
                hideView(errorView);

                showEmptyView();
                break;
            case ViewStatus.ERROR_STATUS:
                hideView(mChildView);
                hideView(loadingView);
                hideView(emptyView);

                showErrorView();
                break;
            default:
                hideView(loadingView);
                hideView(emptyView);
                hideView(errorView);

                mChildView.setVisibility(VISIBLE);
                break;
        }
    }

    /**
     * 设置展示view (error,empty,loading)
     * */
    public void showView(@ViewStatus.VIEW_STATUS int status) {
        switchView(status);
    }

    /**
     * 获取view (error,empty,loading)
     * */
    public View getView(@ViewStatus.VIEW_STATUS int status) {
        switch (status) {
            case ViewStatus.EMPTY_STATUS:
                return emptyView;
            case ViewStatus.LOADING_STATUS:
                return loadingView;
            case ViewStatus.ERROR_STATUS:
                return errorView;
            case ViewStatus.CONTENT_STATUS:
                return mChildView;
        }
        return null;
    }

    public void autoRefresh(){
        createAnimatorTranslationY(State.REFRESH,
                0, head_height,
                new CallBack() {
                    @Override
                    public void onSuccess() {
                        isRefresh = true;
                        if (refreshListener != null) {
                            refreshListener.refresh();
                        }
                        mHeaderView.loading();
                    }
                });
    }

    /**
     * 结束刷新
     */
    public void finishRefresh() {
        setFinish(State.REFRESH);
    }

    /**
     * 结束加载更多
     */
    public void finishLoadMore() {
        setFinish(State.LOADMORE);
    }

    /**
     * 设置是否启用加载更多
     */
    public void setCanLoadMore(boolean canLoadMore) {
        this.canLoadMore = canLoadMore;
    }

    /**
     * 设置是否启用下拉刷新
     */
    public void setCanRefresh(boolean canRefresh) {
        this.canRefresh = canRefresh;
    }

    /**
     * 设置是下拉刷新头部
     *
     * @param mHeaderView 需实现 HeadView 接口
     */
    public void setHeaderView(HeadView mHeaderView) {
        this.mHeaderView = mHeaderView;
        addHeadView();
    }

    /**
     * 设置是下拉刷新尾部
     *
     * @param mFooterView 需实现 FooterView 接口
     */
    public void setFooterView(FooterView mFooterView) {
        this.mFooterView = mFooterView;
        addFooterView();
    }


    /**
     * 设置刷新控件的高度
     *
     * @param dp 单位为dp
     */
    public void setHeadHeight(int dp) {
        head_height = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 设置加载更多控件的高度
     *
     * @param dp 单位为dp
     */
    public void setFootHeight(int dp) {
        foot_height = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 同时设置加载更多控件和刷新控件的高度
     *
     * @param dp 单位为dp
     */
    public void setAllHeight(int dp) {
        head_height = DisplayUtil.dp2Px(getContext(), dp);
        foot_height = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 同时设置加载更多控件和刷新控件的高度
     *
     * @param refresh  刷新控件的高度 单位为dp
     * @param loadMore 加载控件的高度 单位为dp
     */
    public void setAllHeight(int refresh, int loadMore) {
        head_height = DisplayUtil.dp2Px(getContext(), refresh);
        foot_height = DisplayUtil.dp2Px(getContext(), loadMore);
    }

    /**
     * 设置刷新控件的下拉的最大高度 且必须大于本身控件的高度  最佳为2     *
     * @param dp 单位为dp
     */
    public void setMaxHeadHeight(int dp) {
        if (head_height >= DisplayUtil.dp2Px(getContext(), dp)) {
            return;
        }
        head_height_2 = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 设置加载更多控件的上拉的最大高度 且必须大于本身控件的高度  最佳为2     *
     * @param dp 单位为dp
     */
    public void setMaxFootHeight(int dp) {
        if (foot_height >= DisplayUtil.dp2Px(getContext(), dp)) {
            return;
        }
        foot_height_2 = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度  最佳为2     *
     * @param dp 单位为dp
     */
    public void setAllMaxHeight(int dp) {
        if (head_height >= DisplayUtil.dp2Px(getContext(), dp)) {
            return;
        }
        if (foot_height >= DisplayUtil.dp2Px(getContext(), dp)) {
            return;
        }
        head_height_2 = DisplayUtil.dp2Px(getContext(), dp);
        foot_height_2 = DisplayUtil.dp2Px(getContext(), dp);
    }

    /**
     * 同时设置加载更多控件和刷新控件的最大高度 且必须大于本身控件的高度  最佳为2     *
     * @param refresh  刷新控件下拉的最大高度 单位为dp
     * @param loadMore 加载控件上拉的最大高度 单位为dp
     */
    public void setAllMaxHeight(int refresh, int loadMore) {
        if (head_height >= DisplayUtil.dp2Px(getContext(), refresh)) {
            return;
        }
        if (foot_height >= DisplayUtil.dp2Px(getContext(), loadMore)) {
            return;
        }
        head_height_2 = DisplayUtil.dp2Px(getContext(), refresh);
        foot_height_2 = DisplayUtil.dp2Px(getContext(), loadMore);
    }


}

猜你喜欢

转载自blog.csdn.net/androidwubo/article/details/79035110