贝塞尔曲线学习【1】

贝塞尔曲线学习【1】

今天学习了贝塞尔曲线的相关内容
特别感谢 http://blog.csdn.net/z82367825/article/details/51599245 博文。
具体的理论知识就不写了。
在此处记录下 修改过的 波浪图(由原来的一条增加为3条交替变化)。如下图所示。具体实现可以参考上面的文章。
这里写图片描述
这里是绘制了三条贝塞尔曲线组合而成的效果。代码如下:

package com.zero.bezier.widget.wave;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Shader;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;


public class WaveView extends View {

    /**
     * 波峰
     */
    private float mWavePeak = 35f;
    /**
     * 波槽
     */
    private float mWaveTrough = 35f;
    /**
     * 水位
     */
    private float mWaveHeight = 350f;

    private Paint mPaintWave1;
    private Path mPathWave1;
    private int mWaterColorWave1 = 0x990000FF;

    private Paint mPaintWave2;
    private Path mPathWave2;
    private int mWaterColorWave2 = 0x550000FF;

    private Paint mPaintWave3;
    private Path mPathWave3;
    private int mWaterColorWave3 = 0x220000FF;

    public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public WaveView(Context context) {
        super(context);
        init();
    }

    private void init() {



        mPathWave1 = new Path();
        mPaintWave1 = new Paint();
        mPaintWave1.setAntiAlias(true);
        //mPaintWave1.setStyle(Paint.Style.FILL);
        //mPaintWave1.setColor(mWaterColorWave1);
        //mPaintWave1.setColor(getResources().getColor(android.R.color.holo_blue_bright));

        mPathWave2 = new Path();
        mPaintWave2 = new Paint();
        mPaintWave2.setAntiAlias(true);
        mPaintWave2.setStyle(Paint.Style.FILL);
        mPaintWave2.setColor(mWaterColorWave2);
        //mPaintWave2.setColor(getResources().getColor(android.R.color.holo_red_light));

        mPathWave3 = new Path();
        mPaintWave3 = new Paint();
        mPaintWave3.setAntiAlias(true);
        mPaintWave3.setStyle(Paint.Style.FILL);
        mPaintWave3.setColor(mWaterColorWave3);
        //mPaintWave3.setColor(getResources().getColor(android.R.color.holo_green_light));

        LinearGradient linearGradient = new LinearGradient(
                0,
                0,
                720,
                720,
                mWaterColorWave1,
                mWaterColorWave3,
                Shader.TileMode.CLAMP);
        mPaintWave1.setShader(linearGradient);
    }

    private float mWidth, mHeight;

    private PointF mWave1Start;
    private PointF mWave1Left1, mWave1Left2, mWave1First, mWave1Second, mWave1Right;
    private PointF mWave1ControlLeft1, mWave1ControlLeft2, mWave1ControlFirst, mWave1ControlSecond;

    private PointF mWave2Start;
    private PointF mWave2Left1, mWave2Left2, mWave2First, mWave2Second, mWave2Right;
    private PointF mWave2ControlLeft1, mWave2ControlLeft2, mWave2ControlFirst, mWave2ControlSecond;

    private PointF mWave3Start;
    private PointF mWave3Left1, mWave3Left2, mWave3First, mWave3Second, mWave3Right;
    private PointF mWave3ControlLeft1, mWave3ControlLeft2, mWave3ControlFirst, mWave3ControlSecond;

    private boolean mIsRunning = false;

    private boolean mHasInit = false;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        if (!mHasInit) {
            mWidth = w;
            mHeight = h;
            mHasInit = true;
        }
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!mIsRunning || !mHasInit)
            return;
        mPathWave1.reset();
        mPathWave1.moveTo(mWave1Left1.x, mWave1Left1.y);
        mPathWave1.quadTo(mWave1ControlLeft1.x, mWave1ControlLeft1.y, mWave1Left2.x, mWave1Left2.y);
        mPathWave1.quadTo(mWave1ControlLeft2.x, mWave1ControlLeft2.y, mWave1First.x, mWave1First.y);
        mPathWave1.quadTo(mWave1ControlFirst.x, mWave1ControlFirst.y, mWave1Second.x, mWave1Second.y);
        mPathWave1.quadTo(mWave1ControlSecond.x, mWave1ControlSecond.y, mWave1Right.x, mWave1Right.y);
        mPathWave1.lineTo(mWave1Right.x, mHeight);
        mPathWave1.lineTo(mWave1Left1.x, mHeight);
        mPathWave1.lineTo(mWave1Left1.x, mWave1Left1.y);
        canvas.drawPath(mPathWave1, mPaintWave1);

        mPathWave2.reset();
        mPathWave2.moveTo(mWave2Left1.x, mWave2Left1.y);
        mPathWave2.quadTo(mWave2ControlLeft1.x, mWave2ControlLeft1.y, mWave2Left2.x, mWave2Left2.y);
        mPathWave2.quadTo(mWave2ControlLeft2.x, mWave2ControlLeft2.y, mWave2First.x, mWave2First.y);
        mPathWave2.quadTo(mWave2ControlFirst.x, mWave2ControlFirst.y, mWave2Second.x, mWave2Second.y);
        mPathWave2.quadTo(mWave2ControlSecond.x, mWave2ControlSecond.y, mWave2Right.x, mWave2Right.y);
        mPathWave2.lineTo(mWave2Right.x, mHeight);
        mPathWave2.lineTo(mWave2Left1.x, mHeight);
        mPathWave2.lineTo(mWave2Left1.x, mWave2Left1.y);
        canvas.drawPath(mPathWave2, mPaintWave2);

        mPathWave3.reset();
        mPathWave3.moveTo(mWave3Left1.x, mWave3Left1.y);
        mPathWave3.quadTo(mWave3ControlLeft1.x, mWave3ControlLeft1.y, mWave3Left2.x, mWave3Left2.y);
        mPathWave3.quadTo(mWave3ControlLeft2.x, mWave3ControlLeft2.y, mWave3First.x, mWave3First.y);
        mPathWave3.quadTo(mWave3ControlFirst.x, mWave3ControlFirst.y, mWave3Second.x, mWave3Second.y);
        mPathWave3.quadTo(mWave3ControlSecond.x, mWave3ControlSecond.y, mWave3Right.x, mWave3Right.y);
        mPathWave3.lineTo(mWave3Right.x, mHeight);
        mPathWave3.lineTo(mWave3Left1.x, mHeight);
        mPathWave3.lineTo(mWave3Left1.x, mWave3Left1.y);
        canvas.drawPath(mPathWave3, mPaintWave3);

    }

    private void reset() {
        mWave1Start = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave1Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave1Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
        mWave1First = new PointF(0, mHeight - mWaveHeight);
        mWave1Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
        mWave1Right = new PointF(mWidth, mHeight - mWaveHeight);
        mWave1ControlLeft1 = new PointF(mWave1Left1.x + mWidth / 4f, mWave1Left1.y + mWavePeak);
        mWave1ControlLeft2 = new PointF(mWave1Left2.x + mWidth / 4f, mWave1Left2.y - mWaveTrough);
        mWave1ControlFirst = new PointF(mWave1First.x + mWidth / 4f, mWave1First.y + mWavePeak);
        mWave1ControlSecond = new PointF(mWave1Second.x + mWidth / 4f, mWave1Second.y - mWaveTrough);

        mWave2Start = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave2Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave2Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
        mWave2First = new PointF(0, mHeight - mWaveHeight);
        mWave2Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
        mWave2Right = new PointF(mWidth, mHeight - mWaveHeight);
        mWave2ControlLeft1 = new PointF(mWave2Left1.x + mWidth / 4f, mWave2Left1.y + mWavePeak);
        mWave2ControlLeft2 = new PointF(mWave2Left2.x + mWidth / 4f, mWave2Left2.y - mWaveTrough);
        mWave2ControlFirst = new PointF(mWave2First.x + mWidth / 4f, mWave2First.y + mWavePeak);
        mWave2ControlSecond = new PointF(mWave2Second.x + mWidth / 4f, mWave2Second.y - mWaveTrough);

        mWave3Start = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave3Left1 = new PointF(-mWidth, mHeight - mWaveHeight);
        mWave3Left2 = new PointF(-mWidth / 2f, mHeight - mWaveHeight);
        mWave3First = new PointF(0, mHeight - mWaveHeight);
        mWave3Second = new PointF(mWidth / 2f, mHeight - mWaveHeight);
        mWave3Right = new PointF(mWidth, mHeight - mWaveHeight);
        mWave3ControlLeft1 = new PointF(mWave3Left1.x + mWidth / 4f, mWave3Left1.y + mWavePeak);
        mWave3ControlLeft2 = new PointF(mWave3Left2.x + mWidth / 4f, mWave3Left2.y - mWaveTrough);
        mWave3ControlFirst = new PointF(mWave3First.x + mWidth / 4f, mWave3First.y + mWavePeak);
        mWave3ControlSecond = new PointF(mWave3Second.x + mWidth / 4f, mWave3Second.y - mWaveTrough);
    }

    private class WaveHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == ANIM_START) {
                reset();
                startAnimWave1();
                startAnimWave2();
                startAnimWave3();
                mIsRunning = true;
            }
        }
    }

    private WaveHandler mWaveHandler = new WaveHandler();

    private static final int ANIM_START = 1;

    public void setRunning() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!mHasInit) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                mWaveHandler.sendEmptyMessage(ANIM_START);
            }
        }).start();
    }

    private void startAnimWave1() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(mWave1Start.x, 0);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setDuration(3000);
        valueAnimator.setRepeatCount(Animation.INFINITE);
        //动画效果重复
//        valueAnimator.setRepeatMode(Animation.RESTART);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mWave1Left1.x = (float) animation.getAnimatedValue();
                mWave1Left2 = new PointF(mWave1Left1.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave1First = new PointF(mWave1Left2.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave1Second = new PointF(mWave1First.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave1Right = new PointF(mWave1Second.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave1ControlLeft1 = new PointF(mWave1Left1.x + mWidth / 4f, mWave1Left1.y + mWavePeak);
                mWave1ControlLeft2 = new PointF(mWave1Left2.x + mWidth / 4f, mWave1Left2.y - mWaveTrough);
                mWave1ControlFirst = new PointF(mWave1First.x + mWidth / 4f, mWave1First.y + mWavePeak);
                mWave1ControlSecond = new PointF(mWave1Second.x + mWidth / 4f, mWave1Second.y - mWaveTrough);

                invalidate();
            }
        });

        valueAnimator.start();
    }

    private void startAnimWave2() {

        ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(mWave2Start.x, 0);
        valueAnimator1.setInterpolator(new LinearInterpolator());
        valueAnimator1.setDuration(3000);
        valueAnimator1.setRepeatCount(Animation.INFINITE);

        valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mWave2Left1.x = (float) animation.getAnimatedValue();
                mWave2Left2 = new PointF(mWave2Left1.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave2First = new PointF(mWave2Left2.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave2Second = new PointF(mWave2First.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave2Right = new PointF(mWave2Second.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave2ControlLeft1 = new PointF(mWave2Left1.x + mWidth / 4f, mWave2Left1.y + mWavePeak);
                mWave2ControlLeft2 = new PointF(mWave2Left2.x + mWidth / 4f, mWave2Left2.y - mWaveTrough);
                mWave2ControlFirst = new PointF(mWave2First.x + mWidth / 4f, mWave2First.y + mWavePeak);
                mWave2ControlSecond = new PointF(mWave2Second.x + mWidth / 4f, mWave2Second.y - mWaveTrough);

                invalidate();
            }
        });
        valueAnimator1.setStartDelay(-1800);
        valueAnimator1.start();
    }

    private void startAnimWave3() {

        ValueAnimator valueAnimator1 = ValueAnimator.ofFloat(mWave3Start.x, 0);
        valueAnimator1.setInterpolator(new LinearInterpolator());
        valueAnimator1.setDuration(3000);
        valueAnimator1.setRepeatCount(Animation.INFINITE);

        valueAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mWave3Left1.x = (float) animation.getAnimatedValue();
                mWave3Left2 = new PointF(mWave3Left1.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave3First = new PointF(mWave3Left2.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave3Second = new PointF(mWave3First.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave3Right = new PointF(mWave3Second.x + mWidth / 2f, mHeight - mWaveHeight);
                mWave3ControlLeft1 = new PointF(mWave3Left1.x + mWidth / 4f, mWave3Left1.y + mWavePeak);
                mWave3ControlLeft2 = new PointF(mWave3Left2.x + mWidth / 4f, mWave3Left2.y - mWaveTrough);
                mWave3ControlFirst = new PointF(mWave3First.x + mWidth / 4f, mWave3First.y + mWavePeak);
                mWave3ControlSecond = new PointF(mWave3Second.x + mWidth / 4f, mWave3Second.y - mWaveTrough);

                invalidate();
            }
        });
        valueAnimator1.setStartDelay(-800);
        valueAnimator1.start();
    }
}

此处只记录下自己探索的内容:
1、由一条曲线扩充为多条,是开了多个ValueAnimator来invalidate()视图。
2、为了制造视差,在另外两条曲线的ValueAnimator实例中设定了.setStartDelay()值,使动画的发生值滞后(如果设定正值)或者提前(如果设定负值)。此处,设定了负值,即相位提前,避免在第一个曲线动画开始后,其他曲线存在滞后显示的情况
3、绘制path时,替代使用solid颜色,而是使用gradient实现渐变色
4、下面要探索下,是否 可以只使用一个ValueAnimator即可实现多个贝塞尔曲线交叠显示

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SVG 是一种用于创建矢量图形的语言,其中包含了一些绘制基本图形的元素(如线段、矩形、圆形等),也支持使用贝塞尔曲线绘制更复杂的图形。下面我将介绍如何在 SVG 中使用贝塞尔曲线贝塞尔曲线是一种数学曲线,其形状由一组控制点决定。在 SVG 中,我们可以使用 path 元素来绘制贝塞尔曲线。path 元素的 d 属性表示路径,其中包含了一系列子命令,每个子命令代表了一条线段或一条曲线。 下面是一个简单的贝塞尔曲线的示例: ```html <svg width="100" height="100"> <path d="M 20 80 Q 50 20, 80 80" stroke="black" fill="none"/> </svg> ``` 这个示例绘制了一条起点为 (20, 80),结束点为 (80, 80) 的曲线,并且控制点为 (50, 20)。其中,M 表示移动到指定点,Q 表示绘制二次贝塞尔曲线,stroke 表示线条颜色,fill 表示填充颜色。 如果你想要绘制更复杂的曲线,可以使用更多的子命令,比如 C 表示绘制三次贝塞尔曲线。下面是一个绘制心形的示例: ```html <svg width="100" height="100"> <path d="M 50 10 C 60 10, 70 20, 70 30 C 70 50, 50 70, 30 90 C 10 70, 10 50, 30 30 C 40 20, 50 10, 50 10" stroke="red" fill="none"/> </svg> ``` 这个示例绘制了一个心形,其中 C 表示绘制三次贝塞尔曲线,stroke 表示线条颜色,fill 表示填充颜色。 希望这个简单的教程能够帮助你开始使用 SVG 绘制贝塞尔曲线。如果你需要更深入的学习,可以参考 SVG 的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值