自定义View进阶之贝济埃(或贝塞尔)曲线水波纹绘制
Posted LQS_Android
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义View进阶之贝济埃(或贝塞尔)曲线水波纹绘制相关的知识,希望对你有一定的参考价值。
在Path的系列函数中,除了一些基本的设置和绘图用法外,还有一个强大的工具一一贝济埃曲线 它能将利用 moveTo()、LineTo() 连接的生硬路径变得平滑,也能够实现很多炫酷的效 ,比如水波纹等。
贝济埃曲线的历史:
贝济埃曲线于 1962 年,由法国工程师皮埃尔·贝济埃(Pierre Bézier)所广泛发表,他运用贝济埃曲线来为汽车的主体进行设计,贝济埃曲线最初由保尔·德·卡斯特里奥于1959年运用德.卡斯特里奥算法开发,以稳定数值的方法求出贝济埃曲线(又称为贝塞尔曲线)。
贝塞尔曲线有着很多特殊的性质, 在图形设计和路径规划中应用都非常广泛,在路径规划中贝塞尔曲线完全由其控制点决定其形状,n个控制点对应着n-1阶的贝塞尔曲线,并且可以通过递归的方式来绘制。
一阶贝济埃曲线
二阶贝济埃曲线
三阶贝济埃曲线
同理,还有四阶贝济埃曲线、五阶贝济埃曲线,在android开发中最多用到二阶、三阶贝济埃曲线,所以四、五阶的贝济埃曲线不再总结。
贝济埃曲线开发常用API
/**
* Add a quadratic bezier from the last point, approaching control point
* (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
* this contour, the first point is automatically set to (0,0).
*
* @param x1 The x-coordinate of the control point on a quadratic curve
* @param y1 The y-coordinate of the control point on a quadratic curve
* @param x2 The x-coordinate of the end point on a quadratic curve
* @param y2 The y-coordinate of the end point on a quadratic curve
*/
public void quadTo(float x1, float y1, float x2, float y2) {
isSimplePath = false;
nQuadTo(mNativePath, x1, y1, x2, y2);
}
参数中,(x1,y1)是控制点坐标,(x2,y2)是终点坐标.
/**
* Same as quadTo, but the coordinates are considered relative to the last
* point on this contour. If there is no previous point, then a moveTo(0,0)
* is inserted automatically.
*
* @param dx1 The amount to add to the x-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dy1 The amount to add to the y-coordinate of the last point on
* this contour, for the control point of a quadratic curve
* @param dx2 The amount to add to the x-coordinate of the last point on
* this contour, for the end point of a quadratic curve
* @param dy2 The amount to add to the y-coordinate of the last point on
* this contour, for the end point of a quadratic curve
*/
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
isSimplePath = false;
nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
}
知道了上面,两个二阶贝塞尔曲线的API之后,我们在实际的应用中使用一下:
实例一:利用贝塞尔曲线自定义View跟踪手势轨迹绘制平滑曲线,代码如下:
package com.xw.beziercustom.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Copyright (c)2021 网络科技有限公司
*
* @author: LQS
* @date: 2021/6/11
* @description: 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线
*/
public class BezierGestureTrackView extends View {
private Path mPath = new Path();
private Paint mPaint;
private float mPreX,mPreY;
public BezierGestureTrackView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
/**
* 贝济埃曲线是由起始点、控制点、终点确定平滑过渡、和绘制曲线的。
* 整条线的起始点是通过Path.moveTo(x,y)函数来指定的.
*/
mPath.moveTo(event.getX(),event.getY());
/**
* 定义两个变量 mPreX,mPreY来表示手指的前一个点,这个点是用来做控制点的。
*/
mPreX = event.getX();
mPreY = event.getY();
return true;
}
case MotionEvent.ACTION_MOVE:{
/**
* 计算贝济埃曲线的终点
*/
float endX = (mPreX+event.getX())/2;
float endY = (mPreY+event.getY())/2;
/**
* public void quadTo(float x1 , float y1 , float x2 , float y2)
* 参数中(x1 ,y1) 是控制点坐标,(x2,y2)是终点坐标
*/
mPath.quadTo(mPreX,mPreY,endX,endY);
mPreX = event.getX();
mPreY =event.getY();
invalidate();
}
break;
default:
break;
}
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
canvas.drawPath(mPath,mPaint);
}
}
package com.xw.beziercustom.view;
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.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
/**
* Copyright (c)2021 网络科技有限公司
*
* @author: LQS
* @date: 2021/6/14
* @description: com.xw.beziercustom.view.AnimWaveView
*/
public class AnimWaveView extends View {
private Paint mPaint;
private Path mPath;
private int mItemWaveLength = 1200;
private int dx;
public AnimWaveView(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.FILL);
/**
* 让波纹动起来其实很简单,在调用 path.moveTo()函数的时候,将起始点向右移动即可实现波纹移动
* 而且只要移动一个波长的长度波纹就会重合,就可以实现无限循环移动。
*/
//ValueAnimator对指定值区间(0, mItemWaveLength)做动画运算,我们通过对运算过程做监听来自己操作控件。
ValueAnimator animator = ValueAnimator.ofInt(0, mItemWaveLength);
animator.setDuration(3000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setInterpolator(new LinearInterpolator());
//监听ValueAnimator的动画过程来自己对控件做操作
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
//通过animation.getAnimatedValue()得到动画运算的当前值.
dx = (Integer) animation.getAnimatedValue();
Log.d("getAnimatedValue","animation.getAnimatedValue():"+dx);
postInvalidate();
}
});
animator.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
mPath.reset();
int originY = 300;
int halfWaveLen = mItemWaveLength / 2;
/**
* 将mPath的起始位置向左移动一个波长的的距离,为后续实现波形移动动画做准备。
* 动画的长度为一个波长,将当前值保存在类的成员变量dx中
*/
mPath.moveTo(-mItemWaveLength + dx, originY);
for (int i = -mItemWaveLength; i <= getWidth() + mItemWaveLength; i += mItemWaveLength) {
//画的是一个波长中的前半个波(包含波峰的部分,即dy1为-150,Y轴方向上绘制的点更靠近屏幕顶部)
mPath.rQuadTo(halfWaveLen / 2, -150, halfWaveLen, 0);
//画的是一个波长中的后半个波(包含波谷的部分,即dy1为+150,Y轴方向上绘制的点更远离屏幕顶部)
mPath.rQuadTo(halfWaveLen / 2, 150, halfWaveLen, 0);
}
/**
* 下图中黑线所标出的区域就是利利lineTo()函数闭合的区域, 屏幕两边多出的波形在闭后是看不到的
* lineTo(float x, float y):从最后一点到指定点(x,y)添加一条线。如果没有对此轮廓进行moveTo()调用,则第一个点将自动设置为(0,0)。
*/
mPath.lineTo(getWidth(), getHeight());
mPath.lineTo(0, getHeight());
mPath.close();
canvas.drawPath(mPath, mPaint);
}
}
在布局文件中使用上面自定义的View组件:
<?xml version="1.0" encoding="utf-8"?>
<com.xw.beziercustom.view.AnimWaveView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="300dp"
tools:context=".MainActivity">
</com.xw.beziercustom.view.AnimWaveView>
其中关于通过animation.getAnimatedValue()得到动画运算的当前值,是ValueAnimator对指定值区间(0, mItemWaveLength)做动画运算得到的,它的log输出如下:
D/getAnimatedValue: animation.getAnimatedValue():3
D/getAnimatedValue: animation.getAnimatedValue():138
D/getAnimatedValue: animation.getAnimatedValue():10
D/getAnimatedValue: animation.getAnimatedValue():145
D/getAnimatedValue: animation.getAnimatedValue():17
D/getAnimatedValue: animation.getAnimatedValue():151
D/getAnimatedValue: animation.getAnimatedValue():24
D/getAnimatedValue: animation.getAnimatedValue():158
D/getAnimatedValue: animation.getAnimatedValue():30
D/getAnimatedValue: animation.getAnimatedValue():164
D/getAnimatedValue: animation.getAnimatedValue():37
D/getAnimatedValue: animation.getAnimatedValue():171
D/getAnimatedValue: animation.getAnimatedValue():44
D/getAnimatedValue: animation.getAnimatedValue():178
D/getAnimatedValue: animation.getAnimatedValue():50
D/getAnimatedValue: animation.getAnimatedValue():184
D/getAnimatedValue: animation.getAnimatedValue():57
D/getAnimatedValue: animation.getAnimatedValue():191
D/getAnimatedValue: animation.getAnimatedValue():63
D/getAnimatedValue: animation.getAnimatedValue():198
D/getAnimatedValue: animation.getAnimatedValue():70
D/getAnimatedValue: animation.getAnimatedValue():204
D/getAnimatedValue: animation.getAnimatedValue():77
D/getAnimatedValue: animation.getAnimatedValue():211
D/getAnimatedValue: animation.getAnimatedValue():84
D/getAnimatedValue: animation.getAnimatedValue():218
D/getAnimatedValue: animation.getAnimatedValue():90
D/getAnimatedValue: animation.getAnimatedValue():224
D/getAnimatedValue: animation.getAnimatedValue():97
D/getAnimatedValue: animation.getAnimatedValue():231
D/getAnimatedValue: animation.getAnimatedValue():104
D/getAnimatedValue: animation.getAnimatedValue():238
D/getAnimatedValue: animation.getAnimatedValue():110
D/getAnimatedValue: animation.getAnimatedValue():244
D/getAnimatedValue: animation.getAnimatedValue():117
D/getAnimatedValue: animation.getAnimatedValue():251
D/getAnimatedValue: animation.getAnimatedValue():123
D/getAnimatedValue: animation.getAnimatedValue():257
D/getAnimatedValue: animation.getAnimatedValue():130
D/getAnimatedValue: animation.getAnimatedValue():264
D/getAnimatedValue: animation.getAnimatedValue():137
D/getAnimatedValue: animation.getAnimatedValue():271
D/getAnimatedValue: animation.getAnimatedValue():143
D/getAnimatedValue: animation.getAnimatedValue():278
D/getAnimatedValue: animation.getAnimatedValue():150
D/getAnimatedValue: animation.getAnimatedValue():284
D/getAnimatedValue: animation.getAnimatedValue():157
D/getAnimatedValue: animation.getAnimatedValue():291
D/getAnimatedValue: animation.getAnimatedValue():163
D/getAnimatedValue: animation.getAnimatedValue():298
D/getAnimatedValue: animation.getAnimatedValue():170
D/getAnimatedValue: animation.getAnimatedValue():304
D/getAnimatedValue: animation.getAnimatedValue():177
D/getAnimatedValue: animation.getAnimatedValue():311
D/getAnimatedValue: animation.getAnimatedValue():183
D/getAnimatedValue: animation.getAnimatedValue():317
D/getAnimatedValue: animation.getAnimatedValue():190
D/getAnimatedValue: animation.getAnimatedValue():324
D/getAnimatedValue: animation.getAnimatedValue():197
D/getAnimatedValue: animation.getAnimatedValue():331
D/getAnimatedValue: animation.getAnimatedValue():203
D/getAnimatedValue: animation.getAnimatedValue():337
D/getAnimatedValue: animation.getAnimatedValue():210
D/getAnimatedValue: animation.getAnimatedValue():344
D/getAnimatedValue: animation.getAnimatedValue():216
D/getAnimatedValue: animation.getAnimatedValue():351
D/getAnimatedValue: animation.getAnimatedValue():223
D/getAnimatedValue: animation.getAnimatedValue():358
D/getAnimatedValue: animation.getAnimatedValue():230
D/getAnimatedValue: animation.getAnimatedValue():364
D/getAnimatedValue: animation.getAnimatedValue():236
D/getAnimatedValue: animation.getAnimatedValue():371
D/getAnimatedValue: animation.getAnimatedValue():243
D/getAnimatedValue: animation.getAnimatedValue():378
D/getAnimatedValue: animation.getAnimatedValue():250
D/getAnimatedValue: animation.getAnimatedValue():384
D/getAnimatedValue: animation.getAnimatedValue():256
D/getAnimatedValue: animation.getAnimatedValue():391
D/getAnimatedValue: animation.getAnimatedValue():263
D/getAnimatedValue: animation.getAnimatedValue():397
D/getAnimatedValue: animation.getAnimatedValue():270
D/getAnimatedValue: animation.getAnimatedValue():404
D/getAnimatedValue: animation.getAnimatedValue():276
D/getAnimatedValue: animation.getAnimatedValue():411
D/getAnimatedValue: animation.getAnimatedValue():283
D/getAnimatedValue: animation.getAnimatedValue():417
D/getAnimatedValue: animation.getAnimatedValue():290
D/getAnimatedValue: animation.getAnimatedValue():424
D/getAnimatedValue: animation.getAnimatedValue():296
D/getAnimatedValue: animation.getAnimatedValue():431
D/getAnimatedValue: animation.getAnimatedValue():303
D/getAnimatedValue: animation.getAnimatedValue():438
D/getAnimatedValue: animation.getAnimatedValue():310
D/getAnimatedValue: animation.getAnimatedValue():444
D/getAnimatedValue: animation.getAnimatedValue():316
D/getAnimatedValue: animation.getAnimatedValue():451
D/getAnimatedValue: animation.getAnimatedValue():323
D/getAnimatedValue: animation.getAnimatedValue():458
D/getAnimatedValue: animation.getAnimatedValue():329
D/getAnimatedValue: animation.getAnimatedValue():464
D/getAnimatedValue: animation.getAnimatedValue():336
D/getAnimatedValue: animation.getAnimatedValue():471
D/getAnimatedValue: animation.getAnimatedValue():343
D/getAnimatedValue: animation.getAnimatedValue():477
D/getAnimatedValue: animation.getAnimatedValue():350
D/getAnimatedValue: animation.getAnimatedValue():484
D/getAnimatedValue: animation.getAnimatedValue():356
D/getAnimatedValue: animation.getAnimatedValue():491
D/getAnimatedValue: animation.getAnimatedValue():363
D/getAnimatedValue: animation.getAnimatedValue():497
D/getAnimatedValue: animation.getAnimatedValue():370
D/getAnimatedValue: animation.getAnimatedValue():504
D/getAnimatedValue: animation.getAnimatedValue():376
D/getAnimatedValue: animation.getAnimatedValue():511
D/getAnimatedValue: animation.getAnimatedValue():383
D/getAnimatedValue: animation.getAnimatedValue():518
D/getAnimatedValue: animation.getAnimatedValue():389
D/getAnimatedValue: animation.getAnimatedValue():524
D/getAnimatedValue: animation.getAnimatedValue():396
D/getAnimatedValue: animation.getAnimatedValue():531
D/getAnimatedValue: animation.getAnimatedValue():403
D/getAnimatedValue: animation.getAnimatedValue():538
D/getAnimatedValue: animation.getAnimatedValue():409
D/getAnimatedValue: animation.getAnimatedValue():544
D/getAnimatedValue: animation.getAnimatedValue():416
D/getAnimatedValue: animation.getAnimatedValue():551
D/getAnimatedValue: animation.getAnimatedValue():423
D/getAnimatedValue: animation.getAnimatedValue():557
D/getAnimatedValue: animation.getAnimatedValue():430
D/getAnimatedValue: animation.getAnimatedValue():564
D/getAnimatedValue: animation.getAnimatedValue():436
D/getAnimatedValue: animation.getAnimatedValue():571
D/getAnimatedValue: animation.getAnimatedValue():443
D/getAnimatedValue: animation.getAnimatedValue():577
D/getAnimatedValue: animation.getAnimatedValue():450
D/getAnimatedValue: animation.getAnimatedValue():584
D/getAnimatedValue: animation.getAnimatedValue():456
D/getAnimatedValue: animation.getAnimatedValue():591
D/getAnimatedValue: animation.getAnimatedValue():463
D/getAnimatedValue: animation.getAnimatedValue():597
D/getAnimatedValue: animation.getAnimatedValue():469
D/getAnimatedValue: animation.getAnimatedValue():604
D/getAnimatedValue: animation.getAnimatedValue():476
D/getAnimatedValue: animation.getAnimatedValue():611
D/getAnimatedValue: animation.getAnimatedValue():483
D/getAnimatedValue: animation.getAnimatedValue():617
D/getAnimatedValue: animation.getAnimatedValue():490
D/getAnimatedValue: animation.getAnimatedValue():624
D/getAnimatedValue: animation.getAnimatedValue():496
D/getAnimatedValue: animation.getAnimatedValue():631
D/getAnimatedValue: animation.getAnimatedValue():503
D/getAnimatedValue: animation.getAnimatedValue():637
D/getAnimatedValue: animation.getAnimatedValue():510
D/getAnimatedValue: animation.getAnimatedValue():644
D/getAnimatedValue: animation.getAnimatedValue():516
D/getAnimatedValue: animation.getAnimatedValue():651
D/getAnimatedValue: animation.getAnimatedValue():523
D/getAnimatedValue: animation.getAnimatedValue():657
D/getAnimatedValue: animation.getAnimatedValue():529
D/getAnimatedValue: animation.getAnimatedValue():664
D/getAnimatedValue: animation.getAnimatedValue():536
D/getAnimatedValue: animation.getAnimatedValue():670
D/getAnimatedValue: animation.getAnimatedValue():543
D/getAnimatedValue: animation.getAnimatedValue():677
D/getAnimatedValue: animation.getAnimatedValue():549
D/getAnimatedValue: animation.getAnimatedValue():684
D/getAnimatedValue: animation.getAnimatedValue():556
D/getAnimatedValue: animation.getAnimatedValue():690
D/getAnimatedValue: animation.getAnimatedValue():563
D/getAnimatedValue: animation.getAnimatedValue():697
D/getAnimatedValue: animation.getAnimatedValue():570
D/getAnimatedValue: animation.getAnimatedValue():704
D/getAnimatedValue: animation.getAnimatedValue():576
D/getAnimatedValue: animation.getAnimatedValue():710
D/getAnimatedValue: animation.getAnimatedValue():583
D/getAnimatedValue: animation.getAnimatedValue():717
D/getAnimatedValue: animation.getAnimatedValue():590
D/getAnimatedValue: animation.getAnimatedValue():724
D/getAnimatedValue: animation.getAnimatedValue():596
D/getAnimatedValue: animation.getAnimatedValue():730
D/getAnimatedValue: animation.getAnimatedValue():603
D/getAnimatedValue: animation.getAnimatedValue():737
D/getAnimatedValue: animation.getAnimatedValue():609
D/getAnimatedValue: animation.getAnimatedValue():744
D/getAnimatedValue: animation.getAnimatedValue():616
D/getAnimatedValue: animation.getAnimatedValue():750
D/getAnimatedValue: animation.getAnimatedValue():623
D/getAnimatedValue: animation.getAnimatedValue():757
D/getAnimatedValue: animation.getAnimatedValue():629
D/getAnimatedValue: animation.getAnimatedValue():764
D/getAnimatedValue: animation.getAnimatedValue():636
D/getAnimatedValue: animation.getAnimatedValue():770
D/getAnimatedValue: animation.getAnimatedValue():643
D/getAnimatedValue: animation.getAnimatedValue():777
D/getAnimatedValue: animation.getAnimatedValue():649
D/getAnimatedValue: animation.getAnimatedValue():784
D/getAnimatedValue: animation.getAnimatedValue():656
D/getAnimatedValue: animation.getAnimatedValue():790
D/getAnimatedValue: animation.getAnimatedValue():663
D/getAnimatedValue: animation.getAnimatedValue():797
D/getAnimatedValue: animation.getAnimatedValue():669
D/getAnimatedValue: animation.getAnimatedValue():803
D/getAnimatedValue: animation.getAnimatedValue():676
D/getAnimatedValue: animation.getAnimatedValue():810
D/getAnimatedValue: animation.getAnimatedValue():683
D/getAnimatedValue: animation.getAnimatedValue():817
D/getAnimatedValue: animation.getAnimatedValue():689
D/getAnimatedValue: animation.getAnimatedValue():823
D/getAnimatedValue: animation.getAnimatedValue():696
D/getAnimatedValue: animation.getAnimatedValue():830
D/getAnimatedValue: animation.getAnimatedValue():703
D/getAnimatedValue: animation.getAnimatedValue():837
D/getAnimatedValue: animation.getAnimatedValue():709
D/getAnimatedValue: animation.getAnimatedValue():844
D/getAnimatedValue: animation.getAnimatedValue():716
D/getAnimatedValue: animation.getAnimatedValue():850
D/getAnimatedValue: animation.getAnimatedValue():722
D/getAnimatedValue: animation.getAnimatedValue():857
D/getAnimatedValue: animation.getAnimatedValue():729
D/getAnimatedValue: animation.getAnimatedValue():864
D/getAnimatedValue: animation.getAnimatedValue():736
D/getAnimatedValue: animation.getAnimatedValue():870
D/getAnimatedValue: animation.getAnimatedValue():742
D/getAnimatedValue: animation.getAnimatedValue():877
D/getAnimatedValue: animation.getAnimatedValue():749
D/getAnimatedValue: animation.getAnimatedValue():883
D/getAnimatedValue: animation.getAnimatedValue():756
D/getAnimatedValue: animation.getAnimatedValue():890
D/getAnimatedValue: animation.getAnimatedValue():762
D/getAnimatedValue: animation.getAnimatedValue():897
D/getAnimatedValue: animation.getAnimatedValue():769
D/getAnimatedValue: animation.getAnimatedValue():903
D/getAnimatedValue: animation.getAnimatedValue():776
D/getAnimatedValue: animation.getAnimatedValue():910
D/getAnimatedValue: animation.getAnimatedValue():782
D/getAnimatedValue: animation.getAnimatedValue():917
D/getAnimatedValue: animation.getAnimatedValue():789
D/getAnimatedValue: animation.getAnimatedValue():924
D/getAnimatedValue: animation.getAnimatedValue():796
D/getAnimatedValue: animation.getAnimatedValue():930
D/getAnimatedValue: animation.getAnimatedValue():802
D/getAnimatedValue: animation.getAnimatedValue():937
D/getAnimatedValue: animation.getAnimatedValue():809
D/getAnimatedValue: animation.getAnimatedValue():944
D/getAnimatedValue: animation.getAnimatedValue():816
D/getAnimatedValue: animation.getAnimatedValue():950
D/getAnimatedValue: animation.getAnimatedValue():822
D/getAnimatedValue: animation.getAnimatedValue():957
D/getAnimatedValue: animation.getAnimatedValue():829
D/getAnimatedValue: animation.getAnimatedValue():963
D/getAnimatedValue: animation.getAnimatedValue():836
D/getAnimatedValue: animation.getAnimatedValue():970
D/getAnimatedValue: animation.getAnimatedValue():842
D/getAnimatedValue: animation.getAnimatedValue():977
......
D/getAnimatedValue: animation.getAnimatedValue():1177
运行的动画截图如下:
以上是关于自定义View进阶之贝济埃(或贝塞尔)曲线水波纹绘制的主要内容,如果未能解决你的问题,请参考以下文章
自定义控件三部曲之绘图篇——Path之贝赛尔曲线和手势轨迹水波纹效果