Path类的lineTo和quadTo画线

本文介绍如何使用Path类的quadTo方法在Android应用中绘制平滑的贝塞尔曲线,并提供了自定义View和SurfaceView两种实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需要在屏幕上画线时,Path类的应用是必不可少

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

该方法的实现是当我们不仅仅是画一条线甚至是画弧线时会形成平滑的曲线,该曲线又称为"贝塞尔曲线"(Bezier curve),其中,x1,y1为控制点的坐标值,x2,y2为终点的坐标值,贝塞尔曲线的形成,就比如我们把一条橡皮筋拉直,橡皮筋的头尾部对应起点和终点,然后从拉直的橡皮筋中选择任意一点(除头尾对应的点外)扯动橡皮筋形成的弯曲形状,而那个扯动橡皮筋的点就是控制点。

自定义View:

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(Paint.Style.STROKE);
        mGesturePaint.setStrokeWidth(5);  
        mGesturePaint.setColor(Color.RED);
    }  
  
    @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);
//          mPath.lineTo(x, y);//这种比较不圆滑
  
            //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值  
            mX = x;  
            mY = y;  
        }  
    }  }
可以在Activity中加入:setContentView(new DrawingWithBezier(this));  
      

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

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

           




SurfaceView绘制贝塞尔曲线:

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

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(Paint.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;
    }}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值