贝塞尔曲线(一) 认识

来源:互联网 发布:奶酪陷阱 知乎 编辑:程序博客网 时间:2024/05/22 13:05

转载请注明出处:http://blog.csdn.net/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;    }}
1 0