android 下拉刷新终结者

适用于所有页面的下拉刷新package com.wei.demo.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import com.wei.demo.R;

/**
* Created by Administrator on 2017/1/2.
*/

public class RefreshView extends FrameLayout {

private ViewDragHelper dragHelper;
private View mContentView;
private ViewGroup mTopView;
private ListView listView;
private RecyclerView recyclerView;
private ScrollView scrollView;
private ImageView iv_circel;
private RelativeLayout rl_content;

private int mWidth, mHeight;
private int maxRange = 0;//最大下拉的高度
private int refreshHeight;//下拉出发刷新的高度
private int text_bottom;//中间文字的底部

private int downY;
private int childViewTop;

private boolean isMoveChildView, isLayout;//是否包含可滑动的view true包含
private boolean isStop, isStartAnim;//是否停止刷新,是否开启动画

//下拉刷新的状态
private final int STATE_DOWN = 0;//下拉中
private final int STATE_REFRESHING = 1;//刷新中
private final int STATE_REFRESH = 2;//可刷新
private int current_state = STATE_DOWN;

//属性值
private int refresh_gravity = 1;//1 top 2 center 3 bottom
private OnRefreshListener listener;
private boolean isRefresh = true;//是否可以刷新
private TextView tv_text;

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

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

public RefreshView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
    //获取自定义属性
    TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.refreshView);
    refresh_gravity = ta.getInt(R.styleable.refreshView_refresh_gravity, 1);
    ta.recycle();
}

public interface OnRefreshListener {
    void onRefresh();
}

public void setOnRefreshListener(OnRefreshListener listener) {
    this.listener = listener;
}

/**
 * 是否可以刷新
 */
public void setIsRefresh(boolean isRefresh) {
    this.isRefresh = isRefresh;
}

/**
 * 初始化ViewDragHelper
 */
private void init() {
    dragHelper = ViewDragHelper.create(this, 2.0f , new MyCallBack());
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mWidth = w;
    mHeight = h;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    //健壮性检查
    if (getChildCount() > 1) {
        throw new RuntimeException("只能包含一个子view或viewgroup");
    }
    if (getChildCount() == 0) {
        throw new RuntimeException("not childview,childview would not be null!");
    }

    isLayout = false;
    //因为在onFinishInflate中添加一个viewgroup在0的位置
    mContentView = getChildAt(0);//获取布局中的view
    isMoveChildView = childType(mContentView);//查看是否有可滑动的view
    //添加下拉刷新头布局
    mTopView = (ViewGroup) View.inflate(getContext(), R.layout.layout_refresh, null);
    addView(mTopView, 0);

    rl_content = (RelativeLayout) mTopView.findViewById(R.id.fl_header);
    rl_content.measure(0, 0);
    refreshHeight = rl_content.getMeasuredHeight();
    tv_text = (TextView) mTopView.findViewById(R.id.tv_text);
    iv_circel = (ImageView) mTopView.findViewById(R.id.iv_circel);
    iv_circel.setAlpha(0.0f);
    //根据设置的属性设置头布局的位置
    if (refresh_gravity == 1) {
        rl_content.setGravity(Gravity.TOP);
    } else if (refresh_gravity == 2) {
        rl_content.setGravity(Gravity.CENTER);
    } else {
        rl_content.setGravity(Gravity.BOTTOM);
    }

}

/**
 * 判断此view是否是可滑动的view,或此view中是否包含可滑动的view(listview,scrollview,recyclerview)
 *
 * @param view
 * @return true则表示包含可滑动的view
 */
private boolean childType(View view) {
    boolean conform = false;
    conform = isTypeConform(view, conform);
    if (!conform) {
        if (view instanceof ViewGroup) {
            ViewGroup viewGroup = (ViewGroup) view;
            int childCount = viewGroup.getChildCount();
            for (int i = 0; i < childCount; i++) {
                View childView = viewGroup.getChildAt(i);
                if (childView instanceof ViewGroup) {
                    boolean typeConform = isTypeConform(childView, conform);
                    if (typeConform) {
                        childViewTop = childView.getTop();//可滑动view的初始top值
                        return typeConform;
                    }
                    childType(childView);
                }
            }
        }
    }
    return conform;
}

/**
 * 是否是可滑动的view
 */
private boolean isTypeConform(View view, boolean type) {
    if (view instanceof ListView) {
        type = true;
        listView = (ListView) view;
    } else if (view instanceof RecyclerView) {
        recyclerView = (RecyclerView) view;
        type = true;
    } else if (view instanceof ScrollView) {
        scrollView = (ScrollView) view;
        type = true;
    }
    return type;
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    if (!isLayout) {
        if (iv_circel != null && isStartAnim) {
            iv_circel.clearAnimation();
            isStartAnim = false;
            iv_circel.setAlpha(0.0f);
        }
        super.onLayout(changed, left, top, right, bottom);
    }
    maxRange = mHeight - refreshHeight;//最大下拉距离
    text_bottom = refreshHeight - refreshHeight / 2;
    mTopView.layout(0, -(mHeight - refreshHeight), mWidth, refreshHeight);
    isLayout = false;
    //重新摆放刷新布局
    if (refresh_gravity == 1 && mContentView.getTop() >= refreshHeight) {
        mTopView.setTranslationY(mContentView.getTop() - refreshHeight);
    }
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        downY = (int) ev.getY();
    }
    return dragHelper.shouldInterceptTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    dragHelper.processTouchEvent(event);
    return true;
}

private class MyCallBack extends ViewDragHelper.Callback {
    /**
     * 返回可拖拽的范围
     */
    @Override
    public int getViewVerticalDragRange(View child) {
        //如果包含可滑动的view
        if (isMoveChildView && downY > childViewTop) {
            if (listView != null && listView.getAdapter() != null) {
                View childView = listView.getChildAt(0);
                if (listView.getAdapter().getCount() > 0 && childView != null && childView.getTop() < 0)
                    return super.getViewVerticalDragRange(child);
            } else if (scrollView != null && scrollView.getScrollY() > 0) {
                return super.getViewVerticalDragRange(child);
            } else if (recyclerView != null && recyclerView.getAdapter() != null && recyclerView.getChildAt(0).getTop() < 0) {
                return super.getViewVerticalDragRange(child);
            }
        }
        return maxRange;
    }

    /**
     * 返回true表示可以拖拽
     */
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
        //如果触摸的是刷新的头部view  或者是设置为不可刷新则返回false
        if (child == mTopView || !isRefresh) {
            return false;
        }
        return true;
    }

    /**
     * 当被拖拽的view移动位置后,会调用此方法。可以用于处理View之间的联动
     */
    @Override
    public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
        super.onViewPositionChanged(changedView, left, top, dx, dy);
        //处理上面view的移动
        float moveTop = (float) top /** 0.9f*/;
        if (moveTop >= text_bottom) {
            float alpha = (moveTop - text_bottom) / text_bottom;
            if (alpha > 1) {
                alpha = 1.0f;
            } else if (alpha < 0.0) {
                alpha = 0.0f;
            }
            iv_circel.setAlpha(alpha);
        } else {
            iv_circel.setAlpha(0.0f);
        }

        if (tv_text != null) {
            isLayout = true;
            tv_text.setText("下拉刷新");
        }

        if (moveTop >= refreshHeight) {
            if (iv_circel != null && isStartAnim) {
                isStartAnim = false;
                iv_circel.clearAnimation();
            }
            if (refresh_gravity == 1 || refresh_gravity == 2) {
                isLayout = true;
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) rl_content.getLayoutParams();
                params.height = (int) moveTop;
                rl_content.setLayoutParams(params);
                rl_content.requestLayout();
            }
            if (refresh_gravity == 2 || refresh_gravity == 3) {
                float translationY = moveTop - refreshHeight;
                mTopView.setTranslationY(translationY);
            }
        }
    }

    /**
     * 拖拽松开时调用
     */
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
        super.onViewReleased(releasedChild, xvel, yvel);
        int mContentViewTop = mContentView.getTop();
        if (mContentViewTop > refreshHeight) {
            current_state = STATE_REFRESH;
            refreshOpen();
        } else {
            close();
        }
    }

    /**
     * 返回top值
     */
    @Override
    public int clampViewPositionVertical(View child, int top, int dy) {
        float newTop = top /** 0.87f*/;
        if (newTop >= maxRange) {
            newTop = maxRange;
        } else if (top < 0) {
            newTop = 0;
        }
        return (int) newTop;
    }
}

/**
 * 开始刷新 并且滚动至相应的位置
 */
private void refreshOpen() {
    int top = refreshHeight;
    if (dragHelper.smoothSlideViewTo(mContentView, 0, top)) {
        ViewCompat.postInvalidateOnAnimation(this);
    }
}

/**
 * 关闭面板 此时下拉的高度没有达到刷新的高度,滚动至0的位置
 */
private void close() {
    int top = 0;
    if (dragHelper.smoothSlideViewTo(mContentView, 0, top)) {
        ViewCompat.postInvalidateOnAnimation(this);
    }
    mContentView.setFocusable(true);
    isLayout = false;
    current_state = STATE_DOWN;
    iv_circel.clearAnimation();
}

@Override
public void computeScroll() {

// super.computeScroll();
if (dragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
} else if (mContentView.getTop() >= refreshHeight && current_state == STATE_REFRESH) {
startAnim();
current_state = STATE_REFRESHING;//改变状态
if (listener != null) {
listener.onRefresh();
}
if (tv_text != null) {
tv_text.setText(“刷新中”);
isLayout = true;
}
mContentView.setFocusable(false);
}
}

private long duration = 500L;

private void startAnim() {
    isStop = false;
    duration = 500L;
    isStartAnim = true;
    RotateAnimation anim = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F);
    anim.setDuration(duration);
    anim.setRepeatCount(Animation.INFINITE);
    anim.setInterpolator(new LinearInterpolator());
    iv_circel.startAnimation(anim);
    anim.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            current_state = STATE_DOWN;//清楚动画的同时并改变是否刷新的状态
            if (tv_text != null) {
                isLayout = true;
                tv_text.setText("刷新完毕");
            }
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    close();//回滚至顶部
                }
            }, 300);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            if (!isStop) {
                duration -= 100;
                if (duration <= 230) {
                    duration = 230;
                }
            } else {
                duration += 100;
                if (duration >= 500) {
                    duration = 500;
                    anim.setRepeatCount(1);
                }
            }
            anim.setDuration(duration);
        }
    });
}

/**
 * 刷新完毕
 */
public void refreshFinish() {
    isStop = true;
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值