转载请注明出处:http://blog.youkuaiyun.com/darling_R/article/details/68969530
看了徐医宜生 的视频,现在练习了一下贝塞尔曲线,其实挺简单的。下面来看看代码吧
首先借用官方的一个图来演示一下什么是贝塞尔曲线
也可以去[这里]看详细介绍
(https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Linear_curves)
二阶贝塞尔曲线
三阶贝塞尔曲线
二阶效果图:
主要弄清楚 起点 、终点、控制点,然后使用Android提供的贝塞尔曲线api就行了,
二阶的:在onDraw 方法中调用
mPath.quadTo(mFlagPointX, mFlagPointY, mEndPointX, mEndPointY);
前两个参数就是 控制点的坐标,后两个则是终点坐标,起点坐标在初始化path时就确定了,因为绘制曲线,要调用drawpath方法,所以在此之前要定义一个Path,并且在绘制之前,调用reset方法重置,并且,将path移动到起点 mPath.moveTo(mStartPointX,mStartPointY);
重写 OnTouch方法,
case MotionEvent.ACTION_MOVE:
mFlagPointX = event.getX();
mFlagPointY = event.getY();
invalidate();
break;
在手指移动的过程中,记录控制点的坐标,可以让控制点随着手指的移动而移动
在抬起的事件中添加一个动画效果:
case MotionEvent.ACTION_UP:
float mTempX = mStartPointX + (mEndPointX - mStartPointX) / 2;
float mTempY = mStartPointY + (mEndPointY - mStartPointY) / 2;
ValueAnimator valueAnimatorX = ValueAnimator.ofFloat(mFlagPointX,mTempX);
valueAnimatorX.setDuration(500);
valueAnimatorX.setInterpolator(new OvershootInterpolator());
valueAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mFlagPointX = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorX.start();
ValueAnimator valueAnimatorY = ValueAnimator.ofFloat(mFlagPointY,mTempY);
valueAnimatorY.setDuration(500);
valueAnimatorY.setInterpolator(new OvershootInterpolator());
valueAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mFlagPointY = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorY.start();
break;
三阶效果图:
三阶贝塞尔曲线跟二阶差不多,唯一多出来的知识点就是涉及到多点触控,在OnTouch事件里面,
case MotionEvent.ACTION_POINTER_DOWN:
//监听第二根手指按下
isSecond = true;
break;
//多点触控 抬起
case MotionEvent.ACTION_POINTER_UP:
isSecond = false;
break;
mPath.cubicTo(mFlagPointOneX, mFlagPointOneY,mFlagPointTwoX,mFlagPointTwoY, mEndPointX, mEndPointY);
api也有点不同,就是多了控制点的坐标,
二阶跟三阶都有两个方法:rQuadTo(),rCubicTo(),这两个里面的参数都是相对坐标,而quadTo()和cubicTo()参数坐标都是绝对坐标,这里需要注意一下;
这里附上三阶的源码,对应的可以看出来二阶的:
public class ThirdBezierView extends View {
//起点坐标
private float mStartPointX;
private float mStartPointY;
//终点坐标
private float mEndPointY;
private float mEndPointX;
//控制点坐标
private float mFlagPointOneX;
private float mFlagPointOneY;
private float mFlagPointTwoX;
private float mFlagPointTwoY;
//曲线画笔
private Paint mBezierPaint;
//连线画笔
private Paint mLinePaint;
//文字画笔
private Paint mTextPait;
//
private Path mPath;
private boolean isSecond = false;//标志第二个手指是否按下
public ThirdBezierView(Context context) {
super(context);
}
public ThirdBezierView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mBezierPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBezierPaint.setColor(0xfff3a344);
mBezierPaint.setStrokeWidth(8);
mBezierPaint.setStyle(Paint.Style.STROKE);
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setStyle(Paint.Style.STROKE);
mTextPait = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPait.setStyle(Paint.Style.STROKE);
mTextPait.setTextSize(26);
}
public ThirdBezierView(Context context, @Nullable 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);
//初始化坐标点
mStartPointX = w / 4;
mStartPointY = h / 3;
mEndPointX = 3 * w / 4;
mEndPointY = h / 3;
mFlagPointOneX = w / 2 - 200;
mFlagPointOneY = h / 4;
mFlagPointTwoX = w / 2 + 200;
mFlagPointTwoY = h / 4;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPath.reset();
mPath.moveTo(mStartPointX, mStartPointY);
//链接起点与控制点
canvas.drawLine(mStartPointX, mStartPointY, mFlagPointOneX, mFlagPointOneY, mLinePaint);
canvas.drawLine(mFlagPointOneX, mFlagPointOneY, mFlagPointTwoX, mFlagPointTwoY, mLinePaint);
canvas.drawLine(mFlagPointTwoX, mFlagPointTwoY, mEndPointX, mEndPointY, mLinePaint);
canvas.drawText("起点",mStartPointX,mStartPointY,mTextPait);
canvas.drawText("控制点",mFlagPointOneX,mFlagPointOneY,mTextPait);
canvas.drawText("控制点",mFlagPointTwoX,mFlagPointTwoY,mTextPait);
canvas.drawText("终点",mEndPointX,mEndPointY,mTextPait);
mPath.cubicTo(mFlagPointOneX, mFlagPointOneY,mFlagPointTwoX,mFlagPointTwoY, mEndPointX, mEndPointY);
canvas.drawPath(mPath, mBezierPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() &MotionEvent.ACTION_MASK) {
//多点触控标志按下
case MotionEvent.ACTION_POINTER_DOWN:
isSecond = true;
break;
//多点触控 抬起
case MotionEvent.ACTION_POINTER_UP:
isSecond = false;
break;
case MotionEvent.ACTION_MOVE:
mFlagPointOneX = event.getX(0);
mFlagPointOneY = event.getY(0);
if(isSecond){
mFlagPointTwoX = event.getX(1);
mFlagPointTwoY = event.getY(1);
}
invalidate();
break;
}
return true;
}
}