Android初识贝塞尔曲线

Posted 我想月薪过万

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android初识贝塞尔曲线相关的知识,希望对你有一定的参考价值。

贝塞尔曲线 在 android自定义View 中广泛使用,例如:短视频点赞,书面翻页效果等。

我们先来补补 贝塞尔 的由来:

贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由 Paul de Casteljau 于1959年运用de Casteljau 算法开发,以稳定数值的方法求出贝塞尔曲线。

有了上面的历史回顾,下面,我们就来熟悉一下如何用代码 将其 在 Android 中可视化显示出来。

首先,我们来看看二阶贝塞尔曲线:

二阶贝塞尔曲线

效果展示

 源码展示

自定义View代码

package com.wust.mybeisaier;

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;

import androidx.annotation.Nullable;

/**
 * ClassName: selfBeiSaiEr <br/>
 * Description: <br/>
 * date: 2021/7/16 14:30<br/>
 *
 * @author yiqi<br />
 * @QQ 1820762465
 */
public class selfBeiSaiEr extends View {

    private int centerY;
    private int startX;
    private int endX;
    private int eventX;
    private int eventY;
    private Paint mPointPaint;

    public selfBeiSaiEr(Context context) {
        super(context);
    }

    public selfBeiSaiEr(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public selfBeiSaiEr(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    private void initPaint() {
        mPointPaint = getPaintByColor(Color.GRAY);
    }

    private Paint getPaintByColor(int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setColor(color);
        paint.setStyle(Paint.Style.STROKE);

        return paint;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取点的坐标
        centerY = getMeasuredHeight()/2;
        startX = getMeasuredWidth()/2 - 250;
        endX = getMeasuredWidth()/2 + 250;
        eventX = getMeasuredWidth()/2;
        eventY = getMeasuredHeight()/2 - 250;

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画三个点
        mPointPaint.setColor(Color.GRAY);
        canvas.drawCircle(startX,centerY,8,mPointPaint);
        canvas.drawCircle(endX,centerY,8,mPointPaint);
        canvas.drawCircle(eventX,eventY,8,mPointPaint);
        //连线
        Path path = new Path();
        path.moveTo(startX,centerY);
        path.lineTo(eventX,eventY);
        path.lineTo(endX,centerY);
        mPointPaint.setStrokeWidth(5);
        canvas.drawPath(path,mPointPaint);
        //绘制二阶贝塞尔曲线
        Path bPath = new Path();
        bPath.moveTo(startX,centerY);
        bPath.quadTo(eventX,eventY,endX,centerY);
        mPointPaint.setColor(Color.BLUE);
        canvas.drawPath(bPath,mPointPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_POINTER_UP:
            {
                eventX = (int) event.getX();
                eventY = (int) event.getY();
            }
            break;
        }
        invalidate();
        //如果你发现你的 onTouchEvent 无法捕获 MOVE 事件,就是因为这个方法返回的是 false导致的
        System.out.println("super.onTouchEvent(event) -> " + super.onTouchEvent(event));
        return true;
    }
}

 三阶贝塞尔曲线

效果展示

 源码展示

package com.wust.mybeisaier;

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;

import androidx.annotation.Nullable;

/**
 * ClassName: selfBeiSaiEr <br/>
 * Description: <br/>
 * date: 2021/7/16 14:30<br/>
 *
 * @author yiqi<br />
 * @QQ 1820762465
 */
public class selfBeiSaiEr extends View {

    private int centerY;
    private int startX;
    private int endX;
    private int eventX_left;
    private int eventX_right;
    private int eventY_left;
    private int eventY_right;
    private Paint mPointPaint;

    public selfBeiSaiEr(Context context) {
        super(context);
    }

    public selfBeiSaiEr(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint();
    }

    public selfBeiSaiEr(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
    }

    private void initPaint() {
        mPointPaint = getPaintByColor(Color.GRAY);
    }

    private Paint getPaintByColor(int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        paint.setColor(color);
        paint.setStyle(Paint.Style.STROKE);

        return paint;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        centerY = getMeasuredHeight()/2;
        startX = getMeasuredWidth()/2 - 250;
        endX = getMeasuredWidth()/2 + 250;
        eventX_left = startX;
        eventX_right = endX;
        eventY_left = getMeasuredHeight()/2 - 250;
        eventY_right = eventY_left;

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画四个点
        mPointPaint.setColor(Color.GRAY);
        canvas.drawCircle(startX,centerY,8,mPointPaint);
        canvas.drawCircle(endX,centerY,8,mPointPaint);
        canvas.drawCircle(eventX_left,eventY_left,8,mPointPaint);
        canvas.drawCircle(eventX_right,eventY_right,8,mPointPaint);
        //连线
        Path path = new Path();
        path.moveTo(startX,centerY);
        path.lineTo(eventX_left,eventY_left);
        path.lineTo(eventX_right,eventY_right);
        path.lineTo(endX,centerY);
        mPointPaint.setStrokeWidth(5);
        canvas.drawPath(path,mPointPaint);
        //绘制三阶贝塞尔曲线
        Path bPath = new Path();
        bPath.moveTo(startX,centerY);
        bPath.cubicTo(eventX_left,eventY_left,eventX_right,eventY_right,endX,centerY);
        mPointPaint.setColor(Color.BLUE);
        canvas.drawPath(bPath,mPointPaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_POINTER_UP:
            {
                //为了方便,这里我就只让他控制左边点就好了
                eventX_left = (int) event.getX();
                eventY_left = (int) event.getY();
            }
            break;
        }
        invalidate();
        System.out.println("super.onTouchEvent(event) -> " + super.onTouchEvent(event));
        return true;
    }
}

 

以上是关于Android初识贝塞尔曲线的主要内容,如果未能解决你的问题,请参考以下文章

史上最全的贝塞尔曲线(Bezier)全解(一):初识贝塞尔曲线

Android UI贝塞尔曲线 ③ ( 贝塞尔曲线关键点坐标记录 | 二阶贝塞尔曲线示例 )

Android UI贝塞尔曲线 ④ ( 使用 android.graphics.Path 提供的 cubicTo 方法绘制三阶贝塞尔曲线示例 )

Android UI贝塞尔曲线 ⑦ ( 使用 德卡斯特里奥算法 公式计算的 方法绘制三阶贝塞尔曲线示例 )

Android——贝塞尔曲线的水波浪效果实现

从Android动画到贝塞尔曲线