package net.avenwu.support.widget; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.View; import android.view.animation.LinearInterpolator; import net.avenwu.support.R; /** * Created by chaobin on 4/6/15. */ @SuppressWarnings("NewApi") public class BreathingDelegate { private Paint mPaint; private RectF mRippleRect = new RectF(); private float mRippleRadius; private float mEndRadius; private int mRippleAlpha = 0xff; private int mDuration; private RectF mBorderRect = new RectF(); private AnimatorSet mAnimatorSet = new AnimatorSet(); private boolean mAutoStart; private int mRippleColor; private View mTarget; public BreathingDelegate(Context context, AttributeSet attrs, View view) { mTarget = view; mTarget.setWillNotDraw(false); mTarget.setDrawingCacheEnabled(false); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BreathingLayout); mAutoStart = a.getBoolean(R.styleable.BreathingLayout__autoStart, true); mRippleColor = a.getColor(R.styleable.BreathingLayout__rippleColor, 0xFF0099CC); mRippleRadius = a.getDimensionPixelSize(R.styleable.BreathingLayout__rippleStartRadius, -1); if (mRippleRadius == -1) { mRippleRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getContext().getResources().getDisplayMetrics()); } mEndRadius = a.getDimensionPixelSize(R.styleable.BreathingLayout__rippleEndRadius, -1); if (mEndRadius == -1) { mEndRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getContext().getResources().getDisplayMetrics()); } if (mEndRadius <= mRippleRadius) { throw new IllegalStateException("rippleEndRadius can not be smaller than rippleStartRadius"); } mDuration = a.getInt(R.styleable.BreathingLayout__rippleTime, 3000); a.recycle(); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(mRippleColor); mPaint.setStyle(Paint.Style.FILL); prepareAnimation(); if (mAutoStart) { start(); } } Property<BreathingDelegate, Float> mRadiusProperty = new Property<BreathingDelegate, Float>(Float.class, "mRippleRadius") { @Override public Float get(BreathingDelegate object) { return object.getRadius(); } @Override public void set(BreathingDelegate object, Float value) { object.setRadius(value); } }; Property<BreathingDelegate, Integer> mAlphaProperty = new Property<BreathingDelegate, Integer>(Integer.class, "mRippleAlpha") { @Override public Integer get(BreathingDelegate object) { return object.getRippleAlpha(); } @Override public void set(BreathingDelegate object, Integer value) { object.setRippleAlpha(value); } }; private float getRadius() { return mRippleRadius; } private void setRadius(float radius) { this.mRippleRadius = radius; } public int getRippleAlpha() { return mRippleAlpha; } public void setRippleAlpha(int rippleAlpha) { this.mRippleAlpha = rippleAlpha; } private void prepareAnimation() { ObjectAnimator animator = ObjectAnimator.ofFloat(this, mRadiusProperty, mRippleRadius, mEndRadius); animator.setDuration(mDuration); animator.setRepeatCount(ValueAnimator.INFINITE); animator.setRepeatMode(ValueAnimator.REVERSE); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mTarget.invalidate(); } }); ObjectAnimator alpha = ObjectAnimator.ofInt(this, mAlphaProperty, mRippleAlpha, 0x00); alpha.setDuration(mDuration); alpha.setRepeatCount(ValueAnimator.INFINITE); alpha.setRepeatMode(ValueAnimator.RESTART); mAnimatorSet.setInterpolator(new LinearInterpolator()); mAnimatorSet.playTogether(animator, alpha); } public void toggle() { if (mAnimatorSet.isRunning()) { stop(); }/* else if (mAnimatorSet.isPaused()) { mAnimatorSet.resume(); } */ else { mAnimatorSet.start(); } } public void start() { mAnimatorSet.start(); } public void stop() { mAnimatorSet.cancel(); } private Context getContext() { return mTarget.getContext(); } public void onDraw(Canvas canvas) { mRippleRect.set(mBorderRect.centerX() - mRippleRadius, mBorderRect.centerY() - mRippleRadius, mBorderRect.centerX() + mRippleRadius, mBorderRect.centerY() + mRippleRadius); canvas.drawOval(mRippleRect, mPaint); Log.d("BreathingLayout", "onDraw=" + mRippleRect.toString()); } public void onLayout(boolean changed, int left, int top, int right, int bottom) { mBorderRect.set(left, top, right, bottom); Log.d("BreathingLayout", "onLayout:" + mBorderRect.toString()); } public void onDetachedFromWindow() { mAnimatorSet.cancel(); Log.d("BreathingLayout", "onDetachedFromWindow"); } }