RippleView水波紋,漣漪效果
阿新 • • 發佈:2019-01-04
模仿水波紋,漣漪效果,可用於裝置查詢之類的特效
其實這是一個很簡單的自定義View,只需要一個類,然後對外提供狀態回撥介面和設定屬性的方法即可。
下面要說設計思路了。
1,自定義一個View。
2,在onDraw方法裡畫圓,初始化畫筆,半徑多少,要畫幾個圓,實心圓還是空心圓,這些都要想好。
3,通過ValueAnimator 動畫每一貞的回撥改變圓半徑,呼叫postInvalidate方法不斷重繪,就能產生水波紋效果了。
4,設定狀態監聽器,設定注入方法,在該使用的地方回撥一把出去。
5,設定圓的屬性引數的方法。
6,在外面使用。
水波紋自定義View,設計思路就是醬子。
接下來看程式碼詳細的分析上述所說的步驟。
1,自定義一個View。
public class RippleView extends View {
public RippleView(Context context) {
super(context);
init();
}
public RippleView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RippleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
}
2,在onDraw方法裡畫圓,初始化畫筆,半徑多少,要畫幾個圓,實心圓還是空心圓,這些都要想好。
初始化畫筆,半徑。注意mChangeRadius為動畫開始後不斷改變的半徑值,為了不斷畫更大的圓。
private void init() {
mRadius = dip2px(NORMAL_RADIUS);
mChangeRadius = mRadius;
//初始化實心內圓畫筆
mInPaint.setColor(getResources().getColor(R.color.white10));
mInPaint.setAntiAlias(true);
mInPaint.setStyle(Paint.Style.FILL);
//初始化空心內圓畫筆
mInStrokePaint.setColor(getResources().getColor(R.color.white50));
mInStrokePaint.setAntiAlias(true);
mInStrokePaint.setStyle(Paint.Style.STROKE);
mInStrokePaint.setStrokeWidth(dip2px(mStrokeWidth));
//初始化空心外圓畫筆
mOutStrokePaint.setColor(getResources().getColor(R.color.white50));
mOutStrokePaint.setAntiAlias(true);
mOutStrokePaint.setStyle(Paint.Style.STROKE);
mOutStrokePaint.setStrokeWidth(dip2px(mStrokeWidth));
}
初始化圓心
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//初始化圓心
mCx = getMeasuredWidth() / 2;
mCy = getMeasuredHeight() / 2;
}
畫圓。這裡水波紋的圓畫了三個。開始先畫一個,等第一個半徑變為初始值1.5倍時畫第二個圓,2倍畫第三個圓。注意圓半徑的值計算。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//畫半徑變化的外圓
canvas.drawCircle(mCx, mCy, mChangeRadius, mOutStrokePaint);
if(mChangeRadius >= mRadius * 1.5) {
canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius / 2) , mOutStrokePaint);
}
if(mChangeRadius >= mRadius * 2) {
canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius), mOutStrokePaint);
}
//畫實心內圓
canvas.drawCircle(mCx, mCy, mRadius, mInPaint);
//畫空心內圓
canvas.drawCircle(mCx, mCy, mRadius, mInStrokePaint);
}
3,通過ValueAnimator 動畫每一貞的回撥改變圓半徑,呼叫postInvalidate方法不斷重繪,就能產生水波紋效果了。
動畫值的變化區域這裡設定為:
mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));
設定開啟水波紋動畫和關閉水波紋動畫的方法。
/** 開啟水波紋 */
public void startRipple() {
if (mValueAnimator == null) {
mValueAnimator = new ValueAnimator();
mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));
mValueAnimator.setDuration(mDuration);
mValueAnimator.setRepeatCount(mRepeatCount);
mValueAnimator.addUpdateListener(this);
mValueAnimator.addListener(this);
mValueAnimator.start();
} else {
if (!mValueAnimator.isRunning()) {
mValueAnimator.start();
}
}
}
/** 關閉水波紋 */
public void stopRipple() {
if (mValueAnimator != null) {
mValueAnimator.end();
}
}
處理每一貞動畫的邏輯。計算出最新的半徑值給圓,然後不斷重繪。
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeRadius = (int) animation.getAnimatedValue();
postInvalidate();
if (mRippleStateListener != null) {
mRippleStateListener.onRippleUpdate(animation);
}
}
設定狀態監聽器,設定注入方法,在該使用的地方回撥一把出去。
/** 對外提供狀態資訊的介面 */
public interface RippleStateListener {
/** 動畫開始 */
void startRipple();
/** 動畫結束 */
void stopRipple();
/** 每一貞動畫回撥 */
void onRippleUpdate(ValueAnimator animation);
}
/** 水波紋狀態介面物件注入 */
public void setRippleStateListener(RippleStateListener listener) {
mRippleStateListener = listener;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeRadius = (int) animation.getAnimatedValue();
postInvalidate();
if (mRippleStateListener != null) {
mRippleStateListener.onRippleUpdate(animation);
}
}
@Override
public void onAnimationStart(Animator animation) {
if (mRippleStateListener != null) {
mRippleStateListener.startRipple();
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (mRippleStateListener != null) {
mRippleStateListener.stopRipple();
}
//動畫結束,初始變化的半徑
mChangeRadius = mRadius;
}
5,設定圓的屬性引數的方法。
/** 設定圓半徑 */
public void setRadius(int radius) {
mRadius = radius;
mChangeRadius = radius;
}
/** 設定圓邊線寬度 */
public void setStrokeWidth(int strokeWidth) {
mStrokeWidth = strokeWidth;
}
/** 設定動畫時間 */
public void setDuration(int duration) {
mDuration = duration;
}
/** 設定動畫次數 */
public void setRepeatCount(int repeatCount) {
mRepeatCount = repeatCount;
}
/** 設定圓心 */
public void setCirclePoint(float x ,float y) {
mCx = x;
mCy = y;
}
/** 設定空心外圓顏色 */
public void setOutStrokePaintColor(int color) {
mOutStrokePaint.setColor(color);
}
/** 設定空心內圓顏色 */
public void setInStrokePaintColor(int color) {
mInStrokePaint.setColor(color);
}
/** 設定實心內圓顏色 */
public void setInPaintColor(int color) {
mInPaint.setColor(color);
}
6,在外面使用。
mRippleView = (RippleView) findViewById(R.id.root_rv);
mRippleView.setRippleStateListener(this);
public void start(View v) {
mRippleView.startRipple();
}
public void stop(View v) {
mRippleView.stopRipple();
}
@Override
public void startRipple() {
mTextView.setText("0%");
}
@Override
public void stopRipple() {
}
@Override
public void onRippleUpdate(ValueAnimator animation) {
float fraction = animation.getAnimatedFraction();
int value = (int) (fraction * 100);
mTextView.setText(String.valueOf(value) + "%");
}
漣漪,水波紋自定義就這樣分析完了。
再來看一次效果圖:
就到這裡了,小程式一枚。
2016年7月02日 18:00:21