自定義 呼吸燈 閃爍效果 View
原理:根據屬性動畫的因子,在規定時間內,讓某些屬性持續性增加或者減少
說明:本案例只是最基本的原理,知道原理了可以無限擴展需求,連自定義屬性都沒寫,反正已經滿足我的需求了,哈哈,有需要可以自行完善;這種呼吸燈效果一般用于地圖定位點顯示,股票當前點顯示提醒,反正是用于特別提示用戶的地方都可以,一閃一閃亮晶晶
github地址,可直接依賴使用
demo.gif
package com.example.wangjianfeng.blnwaveview;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* author:JianFeng
* date:17/4/26:下午2:30
* description:呼吸燈效果的View
* 原理:在指定時間內,遞減透明色,遞增半徑
*/
public class BreatheView extends View implements ValueAnimator.AnimatorUpdateListener {
private static final String TAG = "BreatheView";
/**
* 擴散圓圈顏色
*/
private int mColor = getResources().getColor(R.color.colorAccent);
/**
* 圓圈中心顏色
*/
private int mCoreColor = getResources().getColor(R.color.colorPrimary);
/**
* 中心圓半徑
*/
private float mCoreRadius = 30f;
/**
* 整個繪制面的最大寬度
*/
private float mMaxWidth = 40f;
/***
* 初始透明度
*/
private int color = 255;
/**
* 是否正在擴散中
*/
private boolean mIsDiffuse = false;
private Paint mPaint;
private float mFraction;//變化因子
private ValueAnimator mAnimator;
private static final long HEART_BEAT_RATE = 2000;//每隔多久閃爍一次
private Handler mHandler;
//圓圈中心坐標
private float circleX ;
private float circleY ;
public BreatheView(Context context) {
this(context, null);
}
public BreatheView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BreatheView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setAntiAlias(true);
mAnimator = ValueAnimator.ofFloat(0, 1f).setDuration(2000);
mAnimator.addUpdateListener(this);
if (null == mHandler) {
mHandler = new Handler();
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
circleX = w /2 ;
circleY = h /2 ;
}
/***
* 設置中心圓半徑
*
* @param radius
*/
public void setCoreRadius(float radius) {
mCoreRadius = radius;
}
/***
* 設置閃爍圓圈最大半徑
*
* @param width
*/
public void setMaxWidth(float width) {
mMaxWidth = width;
}
public void setCoordinate(float x, float y) {
circleX = x;
circleY = y;
}
@Override
public void invalidate() {
if (hasWindowFocus()) {
super.invalidate();
}
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
invalidate();
}
}
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
start();
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
public void onConnected() {
mHandler.removeCallbacks(heartBeatRunnable);
mHandler.post(heartBeatRunnable);
}
public void onDestroy() {
mIsDiffuse = false;
mHandler.removeCallbacks(heartBeatRunnable);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mIsDiffuse) {
//繪制擴散圓
mPaint.setColor(mColor);
mPaint.setAlpha((int) (color - color * mFraction));
canvas.drawCircle(circleX, circleY, mCoreRadius + mMaxWidth * mFraction, mPaint);
// 繪制中心圓
mPaint.setAlpha(255);
mPaint.setColor(mCoreColor);
canvas.drawCircle(circleX, circleY, mCoreRadius, mPaint);
}
invalidate();
}
public void start() {
mIsDiffuse = true;
mAnimator.start();
Log.e(TAG, "閃爍開始");
invalidate();
}
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mFraction = (float) valueAnimator.getAnimatedValue();
Log.e(TAG, "mFraction:" + mFraction);
}
}