Android 贝塞尔曲线菜鸟起步

来源:互联网 发布:粑粑是什么网络意思 编辑:程序博客网 时间:2024/05/02 05:42

一、基本认识

贝塞尔曲线(Bezier curve)是应用于二维图形程序的数学曲线。

一阶贝塞尔曲线:

是一条直线,只有起点和终点,实现方法:

canvas.drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) ;

二阶贝塞尔曲线:

有起点和终点、一个控制点的曲线,实现方法:

 path.moveTo(startX, startY); //移至起点 path.quadTo(controlX, controlY, endX, endY); //二阶曲线,参数是控制点和终点坐标

三阶贝塞尔曲线:

有起点和终点、两个控制点的曲线,实现方法:

path.moveTo(startX, startY);path.cubicTo(controlX1, controlY1, controlX2, controlY2, endX, endY); //三阶曲线,参数是控制点1、控制点2和终点坐标

展示一张效果图:

效果图

以下我将会实现图中的效果。

二、二阶贝塞尔曲线View

自定义一个SecondBezierView继承自View。

首先,在构造方法中,初始化我们的画笔和其他变量:

public SecondBezierView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        mLinePaint = new Paint();        mLinePaint.setAntiAlias(true);        mLinePaint.setDither(true);        mLinePaint.setColor(Color.parseColor("#454545"));        mBezierPaint = new Paint();        mBezierPaint.setAntiAlias(true);        mBezierPaint.setDither(true);        mBezierPaint.setColor(Color.RED);        mBezierPaint.setStyle(Paint.Style.STROKE);        mBezierPaint.setStrokeWidth(3);        mBezierPath = new Path();    }

然后,在onMeasure方法中明确我们贝塞尔曲线的起始点坐标、终点坐标和控制点坐标,这里让它处在居中的位置:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    super.onMeasure(widthMeasureSpec, heightMeasureSpec);    mStartX = 50;    mStartY = getMeasuredHeight() / 2;    mEndX = getMeasuredWidth() - 50;    mEndY = getMeasuredHeight() / 2;    mControlX = (mStartX + mEndX) / 2;    mControlY = (mStartY + mEndY) / 2;}

接下来,就该在onDraw方法中绘制我们的曲线了:

@Overrideprotected void onDraw(Canvas canvas) {    super.onDraw(canvas);    canvas.drawCircle(mStartX, mStartY, 5, mLinePaint);    canvas.drawText("起点", mStartX - 10, mStartY - 10, mLinePaint);    canvas.drawCircle(mEndX, mEndY, 5, mLinePaint);    canvas.drawText("终点", mEndX - 10, mEndY - 10, mLinePaint);    canvas.drawCircle(mControlX, mControlY, 5, mLinePaint);    canvas.drawText("控制点", mControlX - 10, mControlY -10 , mLinePaint);    canvas.drawLine(mStartX, mStartY, mControlX, mControlY, mLinePaint);    canvas.drawLine(mEndX, mEndY, mControlX, mControlY, mLinePaint);    mBezierPath.reset(); //path重置,去除掉重复绘制时残留下的线条    mBezierPath.moveTo(mStartX, mStartY); //移至起点    mBezierPath.quadTo(mControlX, mControlY, mEndX, mEndY); //二阶贝塞尔曲线,参数是控制点和终点坐标    canvas.drawPath(mBezierPath, mBezierPaint);}

最后,重写onTouchEvent,让控制点随着我们手指的移动而移动,并在松开手指时(ACTION_UP),让曲线以动画的形式重置:

@Overridepublic boolean onTouchEvent(MotionEvent event) {    switch (event.getAction()) {        case MotionEvent.ACTION_MOVE:        case MotionEvent.ACTION_DOWN:            mControlX = event.getX();            mControlY = event.getY();            invalidate();            break;        case MotionEvent.ACTION_UP:            ValueAnimator animX = ValueAnimator.ofFloat(mControlX, (mStartX + mEndX) / 2);            animX.setDuration(400);            animX.setInterpolator(new OvershootInterpolator());            animX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    mControlX = (float) animation.getAnimatedValue();                    invalidate();                }            });            animX.start();            ValueAnimator animY = ValueAnimator.ofFloat(mControlY, (mStartY + mEndY) / 2);            animY.setDuration(400);            animY.setInterpolator(new OvershootInterpolator());            animY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {                @Override                public void onAnimationUpdate(ValueAnimator animation) {                    mControlY = (float) animation.getAnimatedValue();                    invalidate();                }            });            animY.start();            break;    }    return true;}

三、三阶贝塞尔曲线View

具体实现和二阶贝塞尔曲线相似,只不过这里有两个控制点。

在绘制的时候,需要调用三阶的方法:

mBezierPath.reset();mBezierPath.moveTo(mStartX, mStartY);mBezierPath.cubicTo(mControlX1, mControlY1, mControlX2, mControlY2, mEndX, mEndY); //三阶贝塞尔曲线,参数是控制点1、控制点2和终点坐标canvas.drawPath(mBezierPath, mBezierPaint);

而对于控制点的操纵,这里用到了多点触控:

@Overridepublic boolean onTouchEvent(MotionEvent event) {    switch (event.getAction() & MotionEvent.ACTION_MASK) { //多点触控        case MotionEvent.ACTION_POINTER_DOWN:            mIsSecondPoint = true;            break;        case MotionEvent.ACTION_POINTER_UP:            mIsSecondPoint = false;            break;        case MotionEvent.ACTION_MOVE:        case MotionEvent.ACTION_DOWN:            mControlX1 = event.getX(0);            mControlY1 = event.getY(0);            if (mIsSecondPoint) {                mControlX2 = event.getX(1);                mControlY2 = event.getY(1);            }            invalidate();            break;    ......}

具体请参见我的代码:https://github.com/Yiiip/Bezier

在实际的运用中,贝塞尔曲线可以让你的应用或者控件拥有非常漂亮的特效,和动画结合效果会非常理想。

1 0
原创粉丝点击