package com.lcodecore.tkrefreshlayout.footer; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.support.annotation.ColorInt; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.FrameLayout.LayoutParams; import com.lcodecore.tkrefreshlayout.IBottomView; import com.lcodecore.tkrefreshlayout.utils.DensityUtil; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; /** * Created by lcodecore on 2017/3/7. */ public class BallPulseView extends View implements IBottomView { public static final int DEFAULT_SIZE = 50; //dp private float circleSpacing; private float[] scaleFloats = new float[]{1f, 1f, 1f}; private ArrayList<ValueAnimator> mAnimators; private Map<ValueAnimator, ValueAnimator.AnimatorUpdateListener> mUpdateListeners = new HashMap<>(); private Paint mPaint; public BallPulseView(Context context) { this(context, null); } public BallPulseView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BallPulseView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); int default_size = DensityUtil.dp2px(context, DEFAULT_SIZE); LayoutParams params = new LayoutParams(default_size, default_size, Gravity.CENTER); setLayoutParams(params); circleSpacing = DensityUtil.dp2px(context, 4); mPaint = new Paint(); mPaint.setColor(Color.WHITE); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); } public void setIndicatorColor(int color) { mPaint.setColor(color); } private int normalColor = 0xffeeeeee; private int animatingColor = 0xffe75946; public void setNormalColor(@ColorInt int color) { normalColor = color; } public void setAnimatingColor(@ColorInt int color) { animatingColor = color; } @Override protected void onDraw(Canvas canvas) { float radius = (Math.min(getWidth(), getHeight()) - circleSpacing * 2) / 6; float x = getWidth() / 2 - (radius * 2 + circleSpacing); float y = getHeight() / 2; for (int i = 0; i < 3; i++) { canvas.save(); float translateX = x + (radius * 2) * i + circleSpacing * i; canvas.translate(translateX, y); canvas.scale(scaleFloats[i], scaleFloats[i]); canvas.drawCircle(0, 0, radius, mPaint); canvas.restore(); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAnimators != null) for (int i = 0; i < mAnimators.size(); i++) { mAnimators.get(i).cancel(); } } public void startAnim() { if (mAnimators == null) createAnimators(); if (mAnimators == null) return; if (isStarted()) return; for (int i = 0; i < mAnimators.size(); i++) { ValueAnimator animator = mAnimators.get(i); //when the animator restart , add the updateListener again because they was removed by animator stop . ValueAnimator.AnimatorUpdateListener updateListener = mUpdateListeners.get(animator); if (updateListener != null) { animator.addUpdateListener(updateListener); } animator.start(); } setIndicatorColor(animatingColor); } public void stopAnim() { if (mAnimators != null) { for (ValueAnimator animator : mAnimators) { if (animator != null && animator.isStarted()) { animator.removeAllUpdateListeners(); animator.end(); } } } setIndicatorColor(normalColor); } private boolean isStarted() { for (ValueAnimator animator : mAnimators) { return animator.isStarted(); } return false; } private void createAnimators() { mAnimators = new ArrayList<>(); int[] delays = new int[]{120, 240, 360}; for (int i = 0; i < 3; i++) { final int index = i; ValueAnimator scaleAnim = ValueAnimator.ofFloat(1, 0.3f, 1); scaleAnim.setDuration(750); scaleAnim.setRepeatCount(ValueAnimator.INFINITE); scaleAnim.setStartDelay(delays[i]); mUpdateListeners.put(scaleAnim, new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { scaleFloats[index] = (float) animation.getAnimatedValue(); postInvalidate(); } }); mAnimators.add(scaleAnim); } } @Override public View getView() { return this; } @Override public void onPullingUp(float fraction, float maxHeadHeight, float headHeight) { stopAnim(); } @Override public void startAnim(float maxHeadHeight, float headHeight) { startAnim(); } @Override public void onPullReleasing(float fraction, float maxHeadHeight, float headHeight) { stopAnim(); } @Override public void onFinish() { stopAnim(); } @Override public void reset() { stopAnim(); } }