自定义控件详解(八):贝塞尔曲线

Path类有4个贝塞尔曲线相关方法:

//二阶贝赛尔  
public void quadTo(float x1, float y1, float x2, float y2)  
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)  
//三阶贝赛尔  
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)  
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)  

关于贝塞尔曲线的概念就不讲了,直接看代码使用。

 一、 下面的方法中 ,参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标 

public void quadTo(float x1, float y1, float x2, float y2)  

 大家看到和Path.lineTo()方法有些不一样,它没有起始坐标。

 实际上连续使用quadTo()方法的时候,上一次使用的终点坐标即下一次的起始坐标

 而一开始我们需要用moveTo()来指定一个起始坐标,如果不指定的话,起始坐标默认为左上角(0,0)

 下面通过实现绘图板功能来看一下使用。

public class BSELineView extends View{
    Path path = new Path();
    float mX;
    float mY;
    public BSELineView(Context context) {
        super(context);
    }

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN: {
                path.moveTo(event.getX(), event.getY());   // 触摸按下的时候,记录起始坐标
                mX = event.getX();
                mY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_MOVE: {                // 触摸过程中,用贝塞尔曲线方法 quadTo()记录路径
                path.quadTo(mX, mY, (mX + event.getX()) / 2, (mY + event.getY()) / 2);
                mX = event.getX();
                mY = event.getY();
                invalidate();                              // 刷新view 注意是在UI线程中
                break;
            }
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.set
可以看到我们绘制出来的View 线条比较华润,没有弯折的生硬感。
二、绘制波浪线
public void rQuadTo(float dx1, float dy1, float dx2, float dy2)  
dx1:控制点X坐标,表示相对上一个终点X坐标的位移坐标,可为负值,正值表示相加,负值表示相减;
dy1:控制点Y坐标,相对上一个终点Y坐标的位移坐标。同样可为负值,正值表示相加,负值表示相减;
dx2:终点X坐标,同样是一个相对坐标,相对上一个终点X坐标的位移值,可为负值,正值表示相加,负值表示相减;
dy2:终点Y坐标,同样是一个相对,相对上一个终点Y坐标的位移值。可为负值,正值表示相加,负值表示相减;
这四个参数都是传递的都是相对值,都是相对上一个终点的位移值。 

 举例:

path.moveTo(100,100);  
path.quadTo(300,50,500,500); 

相等于

path.moveTo(100,100);  
path.rQuadTo(200,-50,400,400) 

 实现一个波浪线。

 初始点假设(orginX , orginY) , 控制点(x,rangY)  ,终点(x*2 , 0)    ,  就绘制了一条开口向下的曲线

                                              接着控制点(x,-rangY) , 终点(x*2,0)   ,就接着绘制了一条开口向上的曲线

        int originY = 300;  // 初始点y轴坐标
        int rangeY = 50 ;    // y轴幅度
        int rangeX = 50; //x轴幅度
        path.moveTo(0,originY);
        for (int i = 0; i < getWidth(); i++) {  // x 轴范围小与屏幕宽度
            path.rQuadTo(rangeX,rangeY,rangeX*2,0);
            path.rQuadTo(rangeX,-rangeY,rangeX*2,0);
            i+=(rangeX*2);
        }

完整代码:

public class WaveView extends View{
    Paint paint ;
    Path path;

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

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        path = new Path();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path.reset();
        int originY = 300;  // 初始点y轴坐标
        int rangeY = 50 ;    // y轴幅度
        int rangeX = 50; //x轴幅度
        path.moveTo(0,originY);
        for (int i = 0; i < getWidth(); i++) {  // x 轴范围小与屏幕宽度
            path.rQuadTo(rangeX,rangeY,rangeX*2,0);
            path.rQuadTo(rangeX,-rangeY,rangeX*2,0);
            i+=(rangeX*2);
        }

        canvas.drawPath(path,paint);
    }
}
效果图:
绘制移动的波形图:
public class WaveView extends View{
    Paint paint ;
    Path path;
    int change;
    public WaveView(Context context) {
        super(context);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        path = new Path();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(6);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        path.reset();
        int originY = 300;  // 初始点y轴坐标
        int rangeY = 50 ;    // y轴幅度
        int rangeX = 50; //x轴幅度
        path.moveTo(-rangeX*4+change,originY); // 让初始点在界面左侧4*rangX处, change是移动距离,没2000毫秒重新绘制
        for (int i = 0; i < getWidth(); i+=(rangeX*2)) {  // x 轴范围小与屏幕宽度
            path.rQuadTo(rangeX,rangeY,rangeX*2,0);
            path.rQuadTo(rangeX,-rangeY,rangeX*2,0);

        }
        path.lineTo(getWidth(),getHeight());
        path.lineTo(0,getHeight());
        path.close();

        canvas.drawPath(path,paint);
    }
    public void startAnim(){
        ValueAnimator animator = ValueAnimator.ofInt(0 , 200);
        animator.setDuration(2000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                change = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏搞前端的李蚊子

Html5模拟通讯录人员排序(sen.js)

// JavaScript Document  var PY_Json_Str = ""; var PY_Str_1 = ""; var PY_Str_...

6016
来自专栏我和未来有约会

简练的视图模型 ViewModel

patterns & practices Developer Center 发布了 Unity Application Block 1.2 for Silver...

2199
来自专栏增长技术

App Guide相关

##TourGuide https://github.com/worker8/TourGuide

712
来自专栏MelonTeam专栏

Bitmap 源码阅读笔记

导语: Android 系统上的图片的处理,跟Bitmap 这个类脱不了关系,我们有必要去深入阅读里面的源码,以便在工作中能更好的处理Bitmap相关的问题...

2518
来自专栏码匠的流水账

java9系列(五)Stack-Walking API

java9新增这个类的目的是提供一个标准API用于访问当前线程栈,之前只有Throwable::getStackTrace、Thread::getStackTr...

421
来自专栏余生开发

echarts太阳分布图-饼图来回穿梭

var dom = document.getElementById("container");

1202
来自专栏linux驱动个人学习

高通Audio中ASOC的machine驱动

ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的...

9804
来自专栏码匠的流水账

聊聊HystrixConcurrencyStrategy

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/concurrency/Hystri...

551
来自专栏草根专栏

适合在Markdown里面使用的emoji

因为Markdown里面加颜色需要写html style, 所以对于一些标题, 还是用一下emoji吧: RED APPLE (&#x1F34E;): ? GR...

2714
来自专栏技术之路

wpf键盘记录器

很简单的一个wpf键盘记录器 ? 这个程序我一样用了全局勾子,之前用的都是winform上运行了,前一段时间 在国外的论坛上逛看到了一个wpf能用的就做了一个小...

2035

扫码关注云+社区