package com.cui.trypro.View.circlerefreshlayout;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import com.cui.trypro.R;
import com.cui.trypro.View.circlerefreshlayout.AnimationView;
/**
* Created by zhanglei on 15/7/20.
*
*下拉刷新
*/
public class CircleRefreshLayout extends FrameLayout {
private static String TAG = "pullToRefresh";
private static final long BACK_TOP_DUR = 600;
private static final long REL_DRAG_DUR = 200;
private int mHeaderBackColor = 0xff8b90af;
private int mHeaderForeColor = 0xffffffff;
private int mHeaderCircleSmaller = 6;
private float mPullHeight;
private float mHeaderHeight;
private View mChildView;
private AnimationView mHeader;
private boolean mIsRefreshing;
private float mTouchStartY;
private float mTouchCurY;
private ValueAnimator mUpBackAnimator;
private ValueAnimator mUpTopAnimator;
private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(10);
public CircleRefreshLayout(Context context) {
this(context, null, 0);
}
public CircleRefreshLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
if (getChildCount() > 1) {
throw new RuntimeException("you can only attach one child");
}
setAttrs(attrs);
mPullHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, context.getResources().getDisplayMetrics());
mHeaderHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
this.post(new Runnable() {
@Override
public void run() {
mChildView = getChildAt(0);
addHeaderView();
}
});
}
private void setAttrs(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CirCleRefreshLayout);
mHeaderBackColor = a.getColor(R.styleable.CirCleRefreshLayout_AniBackColor, mHeaderBackColor);
mHeaderForeColor = a.getColor(R.styleable.CirCleRefreshLayout_AniForeColor, mHeaderForeColor);
mHeaderCircleSmaller = a.getInt(R.styleable.CirCleRefreshLayout_CircleSmaller, mHeaderCircleSmaller);
a.recycle();
}
private void addHeaderView() {
mHeader = new AnimationView(getContext());
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
params.gravity = Gravity.TOP;
mHeader.setLayoutParams(params);
addViewInternal(mHeader);
mHeader.setAniBackColor(mHeaderBackColor);
mHeader.setAniForeColor(mHeaderForeColor);
mHeader.setRadius(mHeaderCircleSmaller);
setUpChildAnimation();
}
private void setUpChildAnimation() {
if (mChildView == null) {
return;
}
mUpBackAnimator = ValueAnimator.ofFloat(mPullHeight, mHeaderHeight);
mUpBackAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
if (mChildView != null) {
mChildView.setTranslationY(val);
}
}
});
mUpBackAnimator.setDuration(REL_DRAG_DUR);
mUpTopAnimator = ValueAnimator.ofFloat(mHeaderHeight, 0);
mUpTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
if (mChildView != null) {
mChildView.setTranslationY(val);
}
mHeader.getLayoutParams().height = (int) val;
mHeader.requestLayout();
}
});
mUpTopAnimator.setDuration(BACK_TOP_DUR);
mHeader.setOnViewAniDone(new AnimationView.OnViewAniDone() {
@Override
public void viewAniDone() {
// Log.i(TAG, "should invoke");
mUpTopAnimator.start();
}
});
}
private void addViewInternal(@NonNull View child) {
super.addView(child);
}
@Override
public void addView(View child) {
if (getChildCount() >= 1) {
throw new RuntimeException("you can only attach one child");
}
mChildView = child;
super.addView(child);
setUpChildAnimation();
}
private boolean canChildScrollUp() {
if (mChildView == null) {
return false;
}
return ViewCompat.canScrollVertically(mChildView, -1);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mIsRefreshing) {
return true;
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchStartY = ev.getY();
mTouchCurY = mTouchStartY;
break;
case MotionEvent.ACTION_MOVE:
float curY = ev.getY();
float dy = curY - mTouchStartY;
if (dy > 0 && !canChildScrollUp()) {
return true;
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mIsRefreshing) {
return super.onTouchEvent(event);
}
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mTouchCurY = event.getY();
float dy = mTouchCurY - mTouchStartY;
dy = Math.min(mPullHeight * 2, dy);
dy = Math.max(0, dy);
if (mChildView != null) {
float offsetY = decelerateInterpolator.getInterpolation(dy / 2 / mPullHeight) * dy / 2;
mChildView.setTranslationY(offsetY);
mHeader.getLayoutParams().height = (int) offsetY;
mHeader.requestLayout();
}
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mChildView != null) {
if (mChildView.getTranslationY() >= mHeaderHeight) {
mUpBackAnimator.start();
mHeader.releaseDrag();
mIsRefreshing = true;
if (onCircleRefreshListener != null) {
onCircleRefreshListener.refreshing();
}
} else {
float height = mChildView.getTranslationY();
ValueAnimator backTopAni = ValueAnimator.ofFloat(height, 0);
backTopAni.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
val = decelerateInterpolator.getInterpolation(val / mHeaderHeight) * val;
if (mChildView != null) {
mChildView.setTranslationY(val);
}
mHeader.getLayoutParams().height = (int) val;
mHeader.requestLayout();
}
});
backTopAni.setDuration((long) (height * BACK_TOP_DUR / mHeaderHeight));
backTopAni.start();
}
}
return true;
default:
return super.onTouchEvent(event);
}
}
public void finishRefreshing() {
if (onCircleRefreshListener != null) {
onCircleRefreshListener.completeRefresh();
}
mIsRefreshing = false;
mHeader.setRefreshing(false);
}
private OnCircleRefreshListener onCircleRefreshListener;
public void setOnRefreshListener(OnCircleRefreshListener onCircleRefreshListener) {
this.onCircleRefreshListener = onCircleRefreshListener;
}
public void setOnLoadMoreListener(OnCircleRefreshListener onCircleRefreshListener) {
this.onCircleRefreshListener = onCircleRefreshListener;
}
public interface OnCircleRefreshListener {
void completeRefresh();
void refreshing();
}
}