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:
- 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)
- {
-
- 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)
- {
-
- super.onDraw(canvas);
-
- canvas.drawPath(mPath, mGesturePaint);
- }
-
-
- private void touchDown(MotionEvent event)
- {
-
-
-
- // mPath.reset(); //此方法加上,每次只能画一次,第二次就清除了第一次的轨迹
- float x = event.getX();
- float y = event.getY();
-
- mX = x;
- mY = y;
-
- 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);
-
-
- if (dx >= 3 || dy >= 3)
- {
-
- float cX = (x + previousX) / 2;
- float cY = (y + previousY) / 2;
-
-
- mPath.quadTo(previousX, previousY, cX, cY);
-
-
- mX = x;
- mY = y;
- }
- }
//清除画板
public void clear() {
if (mGesturePaint != null) {
mPath.reset();
invalidate();
}
}
-
- }
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
- {
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
- setContentView(new DrawingWithBezier(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)
- {
-
- 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)
- {
-
- super.onDraw(canvas);
- canvas.drawPath(mPath, mGesturePaint);
- }
-
-
- private void touchDown(MotionEvent event)
- {
-
-
- mPath.reset();
- float x = event.getX();
- float y = event.getY();
-
- mX = x;
- mY = y;
-
-
- 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);
-
-
- 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
- {
- private PaintView mPaintView;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
-
-
- setContentView(new DrawingWithoutBezier(this));
- 在此处添加按钮监听,清除所有轨迹 (此处按钮自己添加)
- //mPaintView.clear(); //清除轨迹
- }
- }
同样地,用该例子绘制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);
-
- }
-
- public void drawCanvas() {
- try {
- canvas = sfh.lockCanvas();
- if (canvas != null) {
- canvas.drawColor(Color.BLACK);
- canvas.drawPath(mPath, mGesturePaint);
- }
- } catch (Exception e) {
-
- } finally {
- if (canvas != null)
- sfh.unlockCanvasAndPost(canvas);
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
-
- 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;
-
-
- mPath.quadTo(previousX, previousY, cX, cY);
-
-
-
-
-
-
- areaToRefresh.union((int) previousX, (int) previousY,
- (int) previousX, (int) previousY);
-
-
-
-
-
- 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
- {
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(new MySurfaceView(this));
-
-
- }
- }
相关代码下载链接:http://download.csdn.net/detail/stevenhu_223/5702603