1. 程式人生 > >自定義view實現水波紋效果

自定義view實現水波紋效果

自定義view實現水波紋效果

參考csdn大神 啟艦的部落格http://blog.csdn.net/harvic880925/article/details/50995587,自己實現了一遍,碰到的坑有2個:
1、記得呼叫mPath.reset(),否則每次的path內容會疊加在一起,就會充滿整個view ,不再出現水波紋效果;
2、程式碼中的呼叫貝塞爾曲線的引數原理要弄明白:其實每次呼叫onDraw()方法時,呼叫了mPath.moveTo(x,y),關鍵需要弄懂這裡的x的意思,我們必須保證每次moveTo(X,Y)的點是一個貝塞爾曲線的起點,把該動畫想象是正弦波,我們希望每次moveTO()的點都應該是原點,這樣才能完整得去確定我們即將繪製的貝塞爾曲線。所以這次的x= -dx。

package com.example.myapplication;


import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import
android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; /** * Created by liudong on 17-9-11. */ public class RippleView extends View { private int rippleY; private int waveLength; private Paint paint; public RippleView(Context context) { super
(context); init(); } void init() { paint = new Paint(); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL); paint.setAntiAlias(true); } public RippleView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); rippleY = getTop() + getHeight() / 2; waveLength = getWidth() / 3; interval = this.getWidth() / 100; interval_y = getHeight() / 100; } public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private Path mPath = new Path(); private int dx;// 0 ->viewWidth private int y_divide = 0; private int y_total = 100; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.reset(); int tempY = rippleY/2; mPath.moveTo(-dx, tempY); for (int i = -dx; i < getWidth(); i += waveLength) { //2次呼叫貝塞爾曲線 mPath.rQuadTo(waveLength / 2, tempY, waveLength, 0); mPath.rQuadTo(waveLength / 2, -tempY, waveLength, 0); } mPath.lineTo(getRight(), getBottom()); mPath.lineTo(0, getBottom()); mPath.close(); canvas.drawPath(mPath, paint); } private float dy; int interval; int interval_y; private int x; private boolean shouldincrete = true; private boolean shouldincrete_Y = true; public void startRippleAnimation() { // 利用動畫實現水波紋 ValueAnimator animator = ValueAnimator.ofInt(getWidth(), 0); animator.setDuration(20000); animator.setRepeatMode(ValueAnimator.RESTART); animator.setRepeatCount(ValueAnimator.INFINITE); animator.setInterpolator(new LinearInterpolator()); animator.addUpdateListener(animation -> { int animatedValue = (int) animation.getAnimatedValue(); float v = animation.getAnimatedFraction() * getHeight(); dy = v; dx = animatedValue; invalidate(); }); animator.start(); // 利用子執行緒實現水波紋 animationThread = new Thread(() -> { while (!isStop) { SystemClock.sleep(60); if (dx > getWidth()) { shouldincrete = false; } else if (dx < 0) { shouldincrete = true; } if (shouldincrete) { dx += interval; } else { dx -= interval; } if (y_divide > getHeight()) { shouldincrete_Y = false; } else if (y_divide < 0) { shouldincrete_Y = true; } if (shouldincrete_Y) { y_divide += interval_y; } else { y_divide -= interval_y; } postInvalidate(); } }); animationThread.start(); } public boolean isStop = false; private Thread animationThread; }