1.贝塞尔二阶曲线
如下图,由起始点A,控制点C,终点B;
在AC上找到一点D,BC上找到一点E,使AD/DC=CE/EB;
连接DE找到一点F使AD/DC=CE/EB=DF/FE;
F即为贝塞尔曲线上一点。
2.Android绘制贝塞尔二阶曲线
Path里面有两个方法可以进行贝塞尔二阶曲线:
//默认起始点 (0,0),控制点(x1,y1),终点(x2,y2)
public void quadTo(float x1, float y1, float x2, float y2) {
isSimplePath = false;
nQuadTo(mNativePath, x1, y1, x2, y2);
}
//相对于上一个控制点(oldX,oldY)的偏移(oldX+dx1,oldY+dy1),相对于上一个终点(x1,y1)的偏移(x1+dx1,y2+dy2)
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
isSimplePath = false;
nRQuadTo(mNativePath, dx1, dy1, dx2, dy2);
}
根据这个即可绘制曲线图:
代码如下
public class WaveView extends View {
private Path mPath;
private Path mLinePath;
private Paint mPaintBezier;
private Paint mPaintLine;
private int mWaveLength;
private int mScreenWidth;
private int mWaveCount;
private ValueAnimator mValueAnimator = null;
private int mOffsetX;
private int mOffsetY;
public WaveView(Context context) {
super(context);
}
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaintBezier = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintBezier.setColor(Color.WHITE);
mPaintBezier.setStrokeWidth(8);
mPaintBezier.setStyle(Paint.Style.FILL_AND_STROKE);
mPaintLine = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setColor(Color.parseColor("#E3EFF0"));
int width = DensityUtil.dpTopx(getContext(), 6);
int interval = DensityUtil.dpTopx(getContext(), 3);
PathEffect effects = new DashPathEffect(new float[]{width, interval, width, interval}, 1);
mPaintLine.setPathEffect(effects);
WindowManager manager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
int height = display.getHeight();
mPaintLine.setStrokeWidth(height);
mLinePath = new Path();
mOffsetY = DensityUtil.dpTopx(getContext(), 20);
}
public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mPath = new Path();
mScreenWidth = w;
mWaveLength = w * 3 / 5;
// 此处多加1,是为了预先加载屏幕外的一个波浪,持续报廊移动时的连续性
mWaveCount = (int) Math.round(mScreenWidth / mWaveLength + 1.5);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制底部线条
mLinePath.reset();
mLinePath.moveTo(0, 0);
mLinePath.lineTo(mScreenWidth, 0);
canvas.drawPath(mLinePath, mPaintLine);
mPath.reset();
mPath.moveTo(-mWaveLength + mOffsetX, getHeight() * 2 / 3);
for (int i = 0; i < mWaveCount; i++) {
// rQuadTo 相对前一位置偏移量
// 上凸波浪
mPath.rQuadTo(mWaveLength / 4, -mOffsetY, mWaveLength / 2, 0);
// 下凹波浪
mPath.rQuadTo(mWaveLength / 4, +mOffsetY, mWaveLength / 2, 0);
}
mPath.lineTo(mScreenWidth, 0);
mPath.lineTo(0, 0);
mPath.close();
canvas.drawPath(mPath, mPaintBezier);
}
public void startAnimation() {
if (mValueAnimator == null) {
// 设置动画运动距离
mValueAnimator = ValueAnimator.ofInt(0, mWaveLength);
mValueAnimator.setDuration(1000);
// 循环
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// 获取偏移量,绘制波浪曲线的X横坐标加上此偏移量,产生移动效果
mOffsetX = (int) valueAnimator.getAnimatedValue();
invalidate();
}
});
}
mValueAnimator.start();
}
public void stopAnimation() {
if (mValueAnimator != null) {
mValueAnimator.pause();
}
}
public boolean getAnimationing(){
if(mValueAnimator!=null){
return !mValueAnimator.isPaused();
}
return false;
}
}
其他
贝塞尔三阶曲线:调用方法和二阶曲线类似
/**
* Add a cubic bezier from the last point, approaching control points
* (x1,y1) and (x2,y2), and ending at (x3,y3). 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 1st control point on a cubic curve
* @param y1 The y-coordinate of the 1st control point on a cubic curve
* @param x2 The x-coordinate of the 2nd control point on a cubic curve
* @param y2 The y-coordinate of the 2nd control point on a cubic curve
* @param x3 The x-coordinate of the end point on a cubic curve
* @param y3 The y-coordinate of the end point on a cubic curve
*/
public void cubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
isSimplePath = false;
nCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}
/**
* Same as cubicTo, but the coordinates are considered relative to the
* current point on this contour. If there is no previous point, then a
* moveTo(0,0) is inserted automatically.
*/
public void rCubicTo(float x1, float y1, float x2, float y2,
float x3, float y3) {
isSimplePath = false;
nRCubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
}