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

简介: Path类有4个贝塞尔曲线相关方法://二阶贝赛尔 public void quadTo(float x1, float y1, float x2, float y2) public void rQuadTo(float dx1, float dy1, float dx2, float ...

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
        Color(Color.GREEN);
        paint.setStrokeWidth(6);

        canvas.drawPath(path,paint);
    }

    public void reset(){   // 重置功能,清除绘制内容,刷新View
        path.reset();
        postInvalidate();
    }
}

 



可以看到我们绘制出来的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();
    }
}

 







 

相关文章
|
计算机视觉
我的Qt作品(6)使用Qt完整解析dxf文件并绘制(支持椭圆和样条曲线)
我的Qt作品(6)使用Qt完整解析dxf文件并绘制(支持椭圆和样条曲线)
1084 0
我的Qt作品(6)使用Qt完整解析dxf文件并绘制(支持椭圆和样条曲线)
|
4月前
如何用Qt抠一个圆形头像出来
如何用Qt抠一个圆形头像出来
|
10月前
|
C++
《QT从基础到进阶·十五》用鼠标绘制矩形(QGraphicsView、QPainter、QGraphicsRectItem)
《QT从基础到进阶·十五》用鼠标绘制矩形(QGraphicsView、QPainter、QGraphicsRectItem)
485 0
|
12月前
|
iOS开发
iOS 贝塞尔曲线绘制滴水效果
iOS 贝塞尔曲线绘制滴水效果
51 0
|
缓存 算法 前端开发
Android自动手绘,圆你儿时画家梦!
Android自动手绘,圆你儿时画家梦!
Android自动手绘,圆你儿时画家梦!
|
C++
duilib corner属性的贴图技巧——让图片自动贴到控件的的某一边或者一角并自适应控件的大小
转载请说明原出处,谢谢~~          Duilib给控件贴图功能可以附带多个属性,各个属性的配合可以达到许多效果。以下是duilib支持的所有贴图属性: 贴图描述:          Duilib的表现力丰富很大程度上得益于贴图描述的简单强大。
1773 0
|
iOS开发 索引
iOS开发CoreGraphics核心图形框架之三——颜色与色彩空间
iOS开发CoreGraphics核心图形框架之三——颜色与色彩空间
574 0
iOS开发CoreGraphics核心图形框架之三——颜色与色彩空间
|
开发工具 C语言
Qt编写自定义控件21-圆弧仪表盘
一、前言 圆弧仪表盘在整个自定义控件大全中也稍微遇到了技术难点,比如背景透明,如果采用以前画圆形画扇形的方式绘制,肯定很难形成背景透明,需要用到切割,最后换了一种绘制方法,采用绘制圆弧的方式,即使用drawArc方法,这个方法有个注意点就是值要16,我也一直没有搞懂为什么要16,帮助文档也是这么写的,那就按照帮助文档来吧,具体也就没有深究下去。
1108 0
|
C#
WPF画图の利用Path画扇形(仅图形)
原文:WPF画图の利用Path画扇形(仅图形) 一、画弧 Path继承自Sharp,以System.Windows.Shapes.Shape为基类,它是一个具有各种方法的控件。 我们先看一段xaml代码: 画出图形的效果如下: 如上红色部门。
3020 0
|
C# API
深入WPF中的图像画刷(ImageBrush)之1——ImageBrush使用举例
原文:深入WPF中的图像画刷(ImageBrush)之1——ImageBrush使用举例 昨天我在《简述WPF中的画刷(Brush)  》中简要介绍了WPF中的画刷的使用。
2049 0