zoukankan      html  css  js  c++  java
  • Android中Path类的lineTo方法和quadTo方法画线的区别

     
     

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

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

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

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

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

           1).自定义View:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.content.Context;  
    4. import android.gesture.GestureStroke;  
    5. import android.graphics.Canvas;  
    6. import android.graphics.Color;  
    7. import android.graphics.Paint;  
    8. import android.graphics.Path;  
    9. import android.graphics.Rect;  
    10. import android.graphics.Paint.Style;  
    11. import android.view.MotionEvent;  
    12. import android.view.View;  
    13. import android.widget.Toast;  
    14.   
    15. public class DrawingWithBezier extends View  
    16. {  
    17.     private float mX;  
    18.     private float mY;  
    19.   
    20.     private final Paint mGesturePaint = new Paint();  
    21.     private final Path mPath = new Path();  
    22.       
    23.     public DrawingWithBezier(Context context)  
    24.     {  
    25.         super(context);  
    26.         mGesturePaint.setAntiAlias(true);  
    27.         mGesturePaint.setStyle(Style.STROKE);  
    28.         mGesturePaint.setStrokeWidth(5);  
    29.         mGesturePaint.setColor(Color.WHITE);  
    30.     }  
    31.   
    32.     @Override  
    33.     public boolean onTouchEvent(MotionEvent event)  
    34.     {  
    35.         // TODO Auto-generated method stub  
    36.         switch (event.getAction())  
    37.         {  
    38.             case MotionEvent.ACTION_DOWN:  
    39.                 touchDown(event);  
    40.                  break;  
    41.             case MotionEvent.ACTION_MOVE:  
    42.                 touchMove(event);  
    43.         }  
    44.         //更新绘制  
    45.         invalidate();  
    46.         return true;  
    47.     }  
    48.   
    49.     @Override  
    50.     protected void onDraw(Canvas canvas)  
    51.     {  
    52.         // TODO Auto-generated method stub  
    53.         super.onDraw(canvas);  
    54.         //通过画布绘制多点形成的图形  
    55.         canvas.drawPath(mPath, mGesturePaint);  
    56.     }  
    57.   
    58.     //手指点下屏幕时调用  
    59.     private void touchDown(MotionEvent event)  
    60.     {  
    61.         
    62.         //mPath.rewind();  
    63.         //重置绘制路线,即隐藏之前绘制的轨迹  
    64.         mPath.reset();  
    65.         float x = event.getX();  
    66.         float y = event.getY();  
    67.           
    68.         mX = x;  
    69.         mY = y;  
    70.         //mPath绘制的绘制起点  
    71.         mPath.moveTo(x, y);  
    72.     }  
    73.       
    74.     //手指在屏幕上滑动时调用  
    75.     private void touchMove(MotionEvent event)  
    76.     {  
    77.         final float x = event.getX();  
    78.         final float y = event.getY();  
    79.   
    80.         final float previousX = mX;  
    81.         final float previousY = mY;  
    82.   
    83.         final float dx = Math.abs(x - previousX);  
    84.         final float dy = Math.abs(y - previousY);  
    85.           
    86.         //两点之间的距离大于等于3时,生成贝塞尔绘制曲线  
    87.         if (dx >= 3 || dy >= 3)  
    88.         {  
    89.             //设置贝塞尔曲线的操作点为起点和终点的一半  
    90.             float cX = (x + previousX) / 2;  
    91.             float cY = (y + previousY) / 2;  
    92.   
    93.             //二次贝塞尔,实现平滑曲线;previousX, previousY为操作点,cX, cY为终点  
    94.             mPath.quadTo(previousX, previousY, cX, cY);  
    95.   
    96.             //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值  
    97.             mX = x;  
    98.             mY = y;  
    99.         }  
    100.     }  
    101.       
    102. }  

           2).MainActivity:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5. import android.view.Window;  
    6. import android.view.WindowManager;  
    7.   
    8. public class MainActivity extends Activity  
    9. {  
    10.     /** Called when the activity is first created. */  
    11.     @Override  
    12.     public void onCreate(Bundle savedInstanceState)  
    13.     {  
    14.         super.onCreate(savedInstanceState);  
    15.         //setContentView(new MySurfaceView(this));  
    16.         setContentView(new DrawingWithBezier(this));  
    17.         //setContentView(new DrawingWithoutBezier(this));        
    18.     }  
    19. }  

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

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

               

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

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

           1). 自定义View:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.content.Context;  
    4. import android.graphics.Bitmap;  
    5. import android.graphics.Canvas;  
    6. import android.graphics.Color;  
    7. import android.graphics.Paint;  
    8. import android.graphics.Path;  
    9. import android.graphics.Bitmap.Config;  
    10. import android.graphics.Paint.Style;  
    11. import android.view.MotionEvent;  
    12. import android.view.View;  
    13. import android.widget.Toast;  
    14.   
    15. public class DrawingWithoutBezier extends View  
    16. {  
    17.     private float mX;  
    18.     private float mY;  
    19.   
    20.     private final Paint mGesturePaint = new Paint();  
    21.     private final Path mPath = new Path();  
    22.       
    23.     public DrawingWithoutBezier(Context context)  
    24.     {  
    25.         super(context);  
    26.         mGesturePaint.setAntiAlias(true);  
    27.         mGesturePaint.setStyle(Style.STROKE);  
    28.         mGesturePaint.setStrokeWidth(5);  
    29.         mGesturePaint.setColor(Color.WHITE);  
    30.     }  
    31.   
    32.     @Override  
    33.     public boolean onTouchEvent(MotionEvent event)  
    34.     {  
    35.         // TODO Auto-generated method stub  
    36.         switch (event.getAction())  
    37.         {  
    38.             case MotionEvent.ACTION_DOWN:  
    39.                 touchDown(event);  
    40.                  break;  
    41.             case MotionEvent.ACTION_MOVE:  
    42.                 touchMove(event);  
    43.         }  
    44.         //更新绘制  
    45.         invalidate();  
    46.         return true;  
    47.     }  
    48.   
    49.     @Override  
    50.     protected void onDraw(Canvas canvas)  
    51.     {  
    52.         // TODO Auto-generated method stub  
    53.         super.onDraw(canvas);  
    54.         canvas.drawPath(mPath, mGesturePaint);  
    55.     }  
    56.   
    57.     //手指点下屏幕时调用  
    58.     private void touchDown(MotionEvent event)  
    59.     {  
    60.         
    61.         //mPath.rewind();  
    62.         mPath.reset();  
    63.         float x = event.getX();  
    64.         float y = event.getY();  
    65.           
    66.         mX = x;  
    67.         mY = y;  
    68.           
    69.         //mPath绘制的绘制起点  
    70.         mPath.moveTo(x, y);  
    71.     }  
    72.       
    73.     //手指在屏幕上滑动时调用  
    74.     private void touchMove(MotionEvent event)  
    75.     {  
    76.         final float x = event.getX();  
    77.         final float y = event.getY();  
    78.   
    79.         final float previousX = mX;  
    80.         final float previousY = mY;  
    81.   
    82.         final float dx = Math.abs(x - previousX);  
    83.         final float dy = Math.abs(y - previousY);  
    84.           
    85.         //两点之间的距离大于等于3时,连接连接两点形成直线  
    86.         if (dx >= 3 || dy >= 3)  
    87.         {  
    88.             //两点连成直线  
    89.             mPath.lineTo(x, y);  
    90.               
    91.             //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值  
    92.             mX = x;  
    93.             mY = y;  
    94.         }  
    95.     }  
    96.       
    97. }  

           2).MainActivity:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5. import android.view.Window;  
    6. import android.view.WindowManager;  
    7.   
    8. public class MainActivity extends Activity  
    9. {  
    10.     /** Called when the activity is first created. */  
    11.     @Override  
    12.     public void onCreate(Bundle savedInstanceState)  
    13.     {  
    14.         super.onCreate(savedInstanceState);  
    15.         //setContentView(new MySurfaceView(this));  
    16.         //setContentView(new DrawingWithBezier(this));  
    17.         setContentView(new DrawingWithoutBezier(this));        
    18.     }  
    19. }  

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

             

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

       3. SurfaceView绘制贝塞尔曲线:

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

           如下代码:

          1).自定义SurfaceView:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.content.Context;  
    4. import android.graphics.Canvas;  
    5. import android.graphics.Color;  
    6. import android.graphics.Paint;  
    7. import android.graphics.Path;  
    8. import android.graphics.Rect;  
    9. import android.graphics.Paint.Style;  
    10. import android.view.MotionEvent;  
    11. import android.view.SurfaceHolder;  
    12. import android.view.SurfaceView;  
    13.   
    14. public class MySurfaceView extends SurfaceView   
    15. {  
    16.     private Context mContex;  
    17.     private float mX;  
    18.     private float mY;  
    19.   
    20.     private SurfaceHolder sfh;  
    21.     private Canvas canvas;  
    22.     private float mCurveEndX;  
    23.     private float mCurveEndY;  
    24.   
    25.     private final Paint mGesturePaint = new Paint();  
    26.     private final Path mPath = new Path();  
    27.     private final Rect mInvalidRect = new Rect();  
    28.       
    29.     private boolean isDrawing;  
    30.   
    31.     public MySurfaceView(Context context)  
    32.     {  
    33.         super(context);  
    34.         mContex = context;  
    35.         sfh = this.getHolder();  
    36.         mGesturePaint.setAntiAlias(true);  
    37.         mGesturePaint.setStyle(Style.STROKE);  
    38.         mGesturePaint.setStrokeWidth(5);  
    39.         mGesturePaint.setColor(Color.WHITE);  
    40.         // TODO Auto-generated constructor stub  
    41.     }  
    42.   
    43.     public void drawCanvas() {  
    44.         try {  
    45.             canvas = sfh.lockCanvas();  
    46.             if (canvas != null) {  
    47.                 canvas.drawColor(Color.BLACK);  
    48.                 canvas.drawPath(mPath, mGesturePaint);  
    49.             }  
    50.         } catch (Exception e) {  
    51.             // TODO: handle exception  
    52.         } finally {  
    53.             if (canvas != null)  
    54.                 sfh.unlockCanvasAndPost(canvas);  
    55.         }  
    56.     }  
    57.       
    58.     @Override  
    59.     public boolean onTouchEvent(MotionEvent event)  
    60.     {  
    61.         // TODO Auto-generated method stub  
    62.         switch (event.getAction())  
    63.         {  
    64.             case MotionEvent.ACTION_DOWN:  
    65.                 touchDown(event);  
    66.                 invalidate();  
    67.                 return true;  
    68.   
    69.             case MotionEvent.ACTION_MOVE:  
    70.                 if (isDrawing)  
    71.                 {  
    72.                     Rect rect = touchMove(event);  
    73.                     if (rect != null) {  
    74.                         invalidate(rect);  
    75.                     }  
    76.                     return true;  
    77.                 }             
    78.                 break;  
    79.             case MotionEvent.ACTION_UP:  
    80.                 if (isDrawing)  
    81.                 {  
    82.                     touchUp(event);  
    83.                     invalidate();  
    84.                     return true;  
    85.                 }  
    86.                 break;          
    87.         }  
    88.         return super.onTouchEvent(event);  
    89.     }  
    90.   
    91.     private void touchDown(MotionEvent event)  
    92.     {  
    93.         isDrawing = true;  
    94.         mPath.reset();  
    95.         float x = event.getX();  
    96.         float y = event.getY();  
    97.           
    98.         mX = x;  
    99.         mY = y;  
    100.           
    101.         mPath.moveTo(x, y);  
    102.           
    103.         mInvalidRect.set((int) x, (int) y, (int) x , (int) y);  
    104.         mCurveEndX = x;  
    105.         mCurveEndY = y;  
    106.     }  
    107.       
    108.     private Rect touchMove(MotionEvent event)  
    109.     {  
    110.         Rect areaToRefresh = null;  
    111.   
    112.         final float x = event.getX();  
    113.         final float y = event.getY();  
    114.   
    115.         final float previousX = mX;  
    116.         final float previousY = mY;  
    117.   
    118.         final float dx = Math.abs(x - previousX);  
    119.         final float dy = Math.abs(y - previousY);  
    120.           
    121.         if (dx >= 3 || dy >= 3)  
    122.         {  
    123.             areaToRefresh = mInvalidRect;  
    124.             areaToRefresh.set((int) mCurveEndX , (int) mCurveEndY ,  
    125.                     (int) mCurveEndX, (int) mCurveEndY);  
    126.               
    127.           //设置贝塞尔曲线的操作点为起点和终点的一半  
    128.             float cX = mCurveEndX = (x + previousX) / 2;  
    129.             float cY = mCurveEndY = (y + previousY) / 2;  
    130.   
    131.             //实现绘制贝塞尔平滑曲线;previousX, previousY为操作点,cX, cY为终点  
    132.             mPath.quadTo(previousX, previousY, cX, cY);  
    133.             //mPath.lineTo(x, y);  
    134.   
    135.             // union with the control point of the new curve  
    136.             /*areaToRefresh矩形扩大了border(宽和高扩大了两倍border), 
    137.              * border值由设置手势画笔粗细值决定 
    138.              */  
    139.             areaToRefresh.union((int) previousX, (int) previousY,  
    140.                     (int) previousX, (int) previousY);  
    141.            /* areaToRefresh.union((int) x, (int) y, 
    142.                     (int) x, (int) y);*/  
    143.   
    144.               
    145.             // union with the end point of the new curve  
    146.             areaToRefresh.union((int) cX, (int) cY ,  
    147.                     (int) cX, (int) cY);  
    148.   
    149.             //第二次执行时,第一次结束调用的坐标值将作为第二次调用的初始坐标值  
    150.             mX = x;  
    151.             mY = y;  
    152.             drawCanvas();  
    153.         }  
    154.         return areaToRefresh;  
    155.     }  
    156.       
    157.     private void touchUp(MotionEvent event)  
    158.     {  
    159.         isDrawing = false;  
    160.     }  
    161. }  

          2). MainActivity:

    1. package com.feixun.hu.pt;  
    2.   
    3. import android.app.Activity;  
    4. import android.os.Bundle;  
    5. import android.view.Window;  
    6. import android.view.WindowManager;  
    7.   
    8. public class MainActivity extends Activity  
    9. {  
    10.     /** Called when the activity is first created. */  
    11.     @Override  
    12.     public void onCreate(Bundle savedInstanceState)  
    13.     {  
    14.         super.onCreate(savedInstanceState);  
    15.         setContentView(new MySurfaceView(this));  
    16.         //setContentView(new DrawingWithBezier(this));  
    17.         //setContentView(new DrawingWithoutBezier(this));        
    18.     }  
    19. }  

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

  • 相关阅读:
    转 SpringCloud服务注册中心比较:Consul vs Zookeeper vs Etcd vs Eureka
    转 微服务的4个设计原则和19个解决方案
    骑士问题
    种树(洛谷P1250)
    你的飞碟在这儿(洛谷P1200)
    Hello world
    [zt][cocos2dxwin32] 安装部署流程整理
    (ZT)关于IAP防止破解的几点
    (ZT)UIImage应用与内存管理
    在Mac上发布QT的程序
  • 原文地址:https://www.cnblogs.com/xgjblog/p/3878104.html
Copyright © 2011-2022 走看看