自定義view實現水波紋效果
阿新 • • 發佈:2018-12-18
自定義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;
}