Android中Path类的lineTo方法和quadTo方法画线的区别

   当我们需要在屏幕上形成画线时,Path类的应用是必不可少的,而Path类的lineToquadTo方法实现的绘制线路形式也是不一样的,下面就以代码的实现来直观的探究这两个方法的功能实现区别;

   1. Path--->quadTo(float x1, float y1, float x2, float y2):

     该方法的实现是当我们不仅仅是画一条线甚至是画弧线时会形成平滑的曲线,该曲线又称为"贝塞尔曲线"(Bezier curve),其中,x1,y1为控制点的坐标值,x2,y2为终点的坐标值;

    贝塞尔曲线的形成,就比如我们把一条橡皮筋拉直,橡皮筋的头尾部对应起点和终点,然后从拉直的橡皮筋中选择任意一点(除头尾对应的点外)扯动橡皮筋形成的弯曲形状,而那个扯动橡皮筋的点就是控制点;

    下就面以一个Demo来结合理解quadTo函数的应用,代码如下:

       1).自定义View:

package com.feixun.hu.pt;

import android.content.Context;
import android.gesture.GestureStroke;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class DrawingWithBezier extends View
{
    private float mX;
    private float mY;

    private final Paint mGesturePaint = new Paint();
    private final Path mPath = new Path();
    
    public DrawingWithBezier(Context context)
    {
        super(context);
        mGesturePaint.setAntiAlias(true);
        mGesturePaint.setStyle(Style.STROKE);
        mGesturePaint.setStrokeWidth(5);
        mGesturePaint.setColor(Color.WHITE);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        // TODO Auto-generated method stub
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                touchDown(event);
                 break;
            case MotionEvent.ACTION_MOVE:
                touchMove(event);
        }
        //更新绘制
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        //通过画布绘制多点形成的图形
        canvas.drawPath(mPath, mGesturePaint);
    }

    //手指点下屏幕时调用
    private void touchDown(MotionEvent event)
    {
      
        //mPath.rewind();
    	//重置绘制路线,即隐藏之前绘制的轨迹
        mPath.reset();
        float x = event.getX();
        float y = event.getY();
        
        mX = x;
        mY = y;
        //mPath绘制的绘制起点
        mPath.moveTo(x, y);
    }
    
    //手指在屏幕上滑动时调用
    private void touchMove(MotionEvent event)
    {
        final float x = event.getX();
        final float y = event.getY();

        final float previousX = mX;
        final float previousY = mY;

        final float dx = Math.abs(x - previousX);
        final float dy = Math.abs(y - previousY);
        
        //两点之间的距离大于等于3时,生成贝塞尔绘制曲线
        if (dx >= 3 || dy >= 3)
        {
            //设置贝塞尔曲线的操作点为起点和终点的一半
            float cX = (x + previousX) / 2;
            float cY = (y + previousY) / 2;

            //二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点
            mPath.quadTo(previousX, previousY, cX, cY);

            //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值
            mX = x;
            mY = y;
        }
    }
    
}

       2).MainActivity:

package com.feixun.hu.pt;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        //setContentView(new MySurfaceView(this));
        setContentView(new DrawingWithBezier(this));
        //setContentView(new DrawingWithoutBezier(this));      
    }
}

该Demo实现用户在手机屏幕上滑动手指时,可根据手指滑动的位置绘制出相应的线条,类似输入法手势的绘制,所以代码中的画笔Paint命名为mGesturePaint;

比如,我们在屏幕上绘制S这个图案,则形成的图案如下: 

           

   2. Path--->lineTo(float x, float y) :

     该方法实现的仅仅是两点连成一线的绘制线路,这样,当我们用这个方法绘制曲线时,缺陷就出来了;下面的例子,同样还是和上面的Demo差不多,只不过Path调用的是lineTo方法,如下:

       1). 自定义View:

package com.feixun.hu.pt;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Bitmap.Config;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class DrawingWithoutBezier extends View
{
    private float mX;
    private float mY;

    private final Paint mGesturePaint = new Paint();
    private final Path mPath = new Path();
    
    public DrawingWithoutBezier(Context context)
    {
        super(context);
        mGesturePaint.setAntiAlias(true);
        mGesturePaint.setStyle(Style.STROKE);
        mGesturePaint.setStrokeWidth(5);
        mGesturePaint.setColor(Color.WHITE);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        // TODO Auto-generated method stub
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                touchDown(event);
                 break;
            case MotionEvent.ACTION_MOVE:
                touchMove(event);
        }
        //更新绘制
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        canvas.drawPath(mPath, mGesturePaint);
    }

    //手指点下屏幕时调用
    private void touchDown(MotionEvent event)
    {
      
        //mPath.rewind();
        mPath.reset();
        float x = event.getX();
        float y = event.getY();
        
        mX = x;
        mY = y;
        
        //mPath绘制的绘制起点
        mPath.moveTo(x, y);
    }
    
    //手指在屏幕上滑动时调用
    private void touchMove(MotionEvent event)
    {
        final float x = event.getX();
        final float y = event.getY();

        final float previousX = mX;
        final float previousY = mY;

        final float dx = Math.abs(x - previousX);
        final float dy = Math.abs(y - previousY);
        
        //两点之间的距离大于等于3时,连接连接两点形成直线
        if (dx >= 3 || dy >= 3)
        {
        	//两点连成直线
            mPath.lineTo(x, y);
            
            //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值
            mX = x;
            mY = y;
        }
    }
    
}

       2).MainActivity:

package com.feixun.hu.pt;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        //setContentView(new MySurfaceView(this));
        //setContentView(new DrawingWithBezier(this));
        setContentView(new DrawingWithoutBezier(this));      
    }
}

同样地,用该例子绘制S形图案,形成的图案如下:

         

   结论 :对比前面quadTo方法绘制的S,lineTo绘制的S在弯曲部分很明显的不能形成平滑的弯曲,会出现明显的两点形成一线的突痕。可能图片看的不是清楚,自行运行这个Demo,然后在屏幕上绘制弯曲曲线或者圆,对比查看他们的形状区别就一目了然;

   3. SurfaceView绘制贝塞尔曲线:

       上面的绘制图案方式都是基于View来绘制,当然,我们也可以结合SurfaceView和Rect来实现绘制贝塞尔曲线,这样绘制的效果相对会比较好,而且效率也相对较高,毕竟相对SurfaceView而言,在动态绘制点线方面较之View更加出色;

       如下代码:

      1).自定义SurfaceView:

package com.feixun.hu.pt;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView 
{
    private Context mContex;
    private float mX;
    private float mY;

    private SurfaceHolder sfh;
    private Canvas canvas;
    private float mCurveEndX;
    private float mCurveEndY;

    private final Paint mGesturePaint = new Paint();
    private final Path mPath = new Path();
    private final Rect mInvalidRect = new Rect();
    
    private boolean isDrawing;

    public MySurfaceView(Context context)
    {
        super(context);
        mContex = context;
        sfh = this.getHolder();
        mGesturePaint.setAntiAlias(true);
        mGesturePaint.setStyle(Style.STROKE);
        mGesturePaint.setStrokeWidth(5);
        mGesturePaint.setColor(Color.WHITE);
        // TODO Auto-generated constructor stub
    }

    public void drawCanvas() {
        try {
            canvas = sfh.lockCanvas();
            if (canvas != null) {
                canvas.drawColor(Color.BLACK);
                canvas.drawPath(mPath, mGesturePaint);
            }
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            if (canvas != null)
                sfh.unlockCanvasAndPost(canvas);
        }
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        // TODO Auto-generated method stub
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                touchDown(event);
                invalidate();
                return true;

            case MotionEvent.ACTION_MOVE:
                if (isDrawing)
                {
                    Rect rect = touchMove(event);
                    if (rect != null) {
                        invalidate(rect);
                    }
                    return true;
                }           
                break;
            case MotionEvent.ACTION_UP:
                if (isDrawing)
                {
                    touchUp(event);
                    invalidate();
                    return true;
                }
                break;        
        }
        return super.onTouchEvent(event);
    }

    private void touchDown(MotionEvent event)
    {
        isDrawing = true;
        mPath.reset();
        float x = event.getX();
        float y = event.getY();
        
        mX = x;
        mY = y;
        
        mPath.moveTo(x, y);
        
        mInvalidRect.set((int) x, (int) y, (int) x , (int) y);
        mCurveEndX = x;
        mCurveEndY = y;
    }
    
    private Rect touchMove(MotionEvent event)
    {
        Rect areaToRefresh = null;

        final float x = event.getX();
        final float y = event.getY();

        final float previousX = mX;
        final float previousY = mY;

        final float dx = Math.abs(x - previousX);
        final float dy = Math.abs(y - previousY);
        
        if (dx >= 3 || dy >= 3)
        {
            areaToRefresh = mInvalidRect;
            areaToRefresh.set((int) mCurveEndX , (int) mCurveEndY ,
                    (int) mCurveEndX, (int) mCurveEndY);
            
          //设置贝塞尔曲线的操作点为起点和终点的一半
            float cX = mCurveEndX = (x + previousX) / 2;
            float cY = mCurveEndY = (y + previousY) / 2;

            //实现绘制贝塞尔平滑曲线;previousX, previousY为操作点,cX, cY为终点
            mPath.quadTo(previousX, previousY, cX, cY);
            //mPath.lineTo(x, y);

            // union with the control point of the new curve
            /*areaToRefresh矩形扩大了border(宽和高扩大了两倍border),
             * border值由设置手势画笔粗细值决定
             */
            areaToRefresh.union((int) previousX, (int) previousY,
                    (int) previousX, (int) previousY);
           /* areaToRefresh.union((int) x, (int) y,
                    (int) x, (int) y);*/

            
            // union with the end point of the new curve
            areaToRefresh.union((int) cX, (int) cY ,
                    (int) cX, (int) cY);

            //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值
            mX = x;
            mY = y;
            drawCanvas();
        }
        return areaToRefresh;
    }
    
    private void touchUp(MotionEvent event)
    {
        isDrawing = false;
    }
}

      2). MainActivity:

package com.feixun.hu.pt;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(new MySurfaceView(this));
        //setContentView(new DrawingWithBezier(this));
        //setContentView(new DrawingWithoutBezier(this));      
    }
}

    相关代码下载链接:http://download.csdn.net/detail/stevenhu_223/5702603

  • 19
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
### 回答1: `QuadTo` 是 `Path` 的一个方法,用于绘制二次贝塞尔曲线。它的语法如下: ```java public void quadTo(float x1, float y1, float x2, float y2) ``` 其 `(x1, y1)` 是控制点的坐标,`(x2, y2)` 是结束点的坐标。控制点决定了曲线的弯曲程度和方向。当画布上的当前点与结束点不重合时,曲线将以当前点作为起点,以结束点作为终点,以控制点确定的曲线形状连接这两个点。 下面是一个例子: ```java Path path = new Path(); path.moveTo(100, 100); // 起点 path.quadTo(200, 50, 300, 100); // 绘制二次贝塞尔曲线 canvas.drawPath(path, paint); ``` 这段代码将在画布上绘制一个起点为 `(100, 100)`,结束点为 `(300, 100)`,控制点为 `(200, 50)` 的二次贝塞尔曲线。 ### 回答2: AndroidquadTo()是一个用于绘制二次贝塞尔曲线的方法。它接受四个参数,分别是贝塞尔曲线的控制点坐标和终点坐标。 贝塞尔曲线是一种用于平滑曲线绘制的数学曲线。二次贝塞尔曲线由起始点、一个控制点和一个终点组成。使用quadTo()方法可以通过设置这些点来绘制出平滑的曲线。 quadTo()方法的第一个参数是控制点的x坐标,第二个参数是控制点的y坐标,第三个参数是终点的x坐标,第四个参数是终点的y坐标。通过这些参数,可以控制曲线的形状和方向。 在绘制二次贝塞尔曲线时,可以使用PathquadTo()方法将曲线添加到路径,然后通过Canvas的drawPath()方法将路径绘制到画布上。 使用quadTo()方法可以创建各种各样的平滑曲线,例如弧线、波浪线、曲线路径等。可以通过调整控制点的位置和终点的位置来改变曲线的形状。 总之,AndroidquadTo()方法是一个用于绘制二次贝塞尔曲线的函数。通过设置控制点和终点的坐标,可以创建各种平滑曲线来实现丰富多样的绘图效果。 ### 回答3: AndroidquadTo()是一个Path方法,用于绘制二次贝塞尔曲线。 二次贝塞尔曲线是指由一个起点、一个控制点和一个终点确定的曲线。通过控制点的位置,可以改变曲线的形状和方向。 在使用quadTo()方法时,需要先创建一个Path对象,并调用moveTo()方法指定起始点的位置。 然后,在调用quadTo()方法之前,需要先调用lineTo()或moveTo()方法来指定控制点的位置。 quadTo()方法的参数是控制点的坐标和终点的坐标,即quadTo(float x1, float y1, float x2, float y2)。 调用quadTo()方法后,Path对象会根据起点、控制点和终点的位置绘制出二次贝塞尔曲线。 值得注意的是,每次调用quadTo()方法后,Path的当前位置会更新为终点的位置。 与curveTo()相比,quadTo()方法只能绘制二次贝塞尔曲线,而curveTo()方法可以绘制更复杂的三次贝塞尔曲线。 使用quadTo()方法可以实现各种曲线效果,如平滑的弧线、圆润的边角以及自由曲线等。 另外,还可以使用rQuadTo()方法来绘制相对位置的二次贝塞尔曲线,其参数与quadTo()方法相似,但是表示相对于当前位置的偏移量。 总而言之,androidquadTo()方法是一个用于绘制二次贝塞尔曲线的函数,通过指定起点、控制点和终点的位置来定义曲线的形状和方向。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值