Android基礎之Path類的使用

Android基礎之Path類的使用

我們知道Android中Canvas類對象可以進行繪製事物,裏面有一個方法爲canvas.drawPath方法,這個方法就是用來繪製我們的自定義Path對象。Path對象很有用,我們可以繪製一些特殊的動畫效果,文字吸附效果等等。所以我們需要來學習下Path對象的使用。

Path對象的方法

一、構造函數

1、無參構造函數

/**
     * Create an empty path
     */
    public Path() {
        mNativePath = init1();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

創建一個空的Path對象。

/**
     * Create a new path, copying the contents from the src path.
     *
     * @param src The path to copy from when initializing the new path
     */
    public Path(Path src) {
        long valNative = 0;
        if (src != null) {
            valNative = src.mNativePath;
            isSimplePath = src.isSimplePath;
            if (src.rects != null) {
                rects = new Region(src.rects);
            }
        }
        mNativePath = init2(valNative);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

創建一個將非空的含有src的Path對象。

二、成員函數

1、 public void moveTo(float x, float y)
移動繪製的起點,從點(x,y)點開始進行繪製。
2、 public void lineTo(float x, float y)
連接起始點與點(x,y)的直線,如果沒有使用moveTo則起始點默認爲(0,0)。

實例1:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.lineTo(300,300);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我們繪製點(0,0)與點(300,300)之間的直線。效果圖: 
lineto

實例2:我們在lineTo之前添加MoveTo方法。

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.moveTo(100,100);
        mPath.lineTo(300,300);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我們將起點移動到點(100,100)繪製點與點(300,300)之間的線。效果圖如圖: 
moveto

3、public void rMoveTo(float dx, float dy)
在繪製線的終點的基礎上移動(dx,dy)得到新的起始點。
實例3:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.lineTo(100,100);
        mPath.rMoveTo(50,50);
        mPath.lineTo(300,300);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我們先進行點(0,0)與點(100,100)之間連線,然後通過rMoveTo方法移動(50,50)個距離,即現在的起點是(150,150),然後繪製到(300,300)之間的直線。
效果圖: 
rmoveto

4、public void rLineTo(float dx, float dy)
與lineTo功能類似,但是是在上個線的終點基礎上進行繪製,不是lineTo的從(0,0)開始。
實例4:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.lineTo(100,50);
        mPath.rLineTo(200,300);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我們先繪製(0,0)到(100,50)之間的線,然後在(100,50)的起點基礎上繪製(300,350)之間的線。
效果圖: 
rlineto

5、public void quadTo(float x1, float y1, float x2, float y2)
根據兩個控制點繪製貝塞爾曲線。如果沒有使用moveTo指定起點,起點默認爲(0,0),即(0,0)到(x1,y1)之間繪製貝塞爾曲線,(x1,y1)到(x2,y2)之間繪製貝塞爾曲線。
實例5:

@Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.quadTo(100,50,300,500);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

效果圖: 
quadTo

6、 public void cubicTo(float x1, float y1, float x2, float y2, 
float x3, float y3)
通過三個控制點繪製貝塞爾曲線。 
實例代碼6:

 @Override
     protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        //爲了增強效果對比,我們繪製出三個控制點之間對應的直線
        mPath.lineTo(100,50);
        mPath.lineTo(200, 300);
        mPath.lineTo(400, 220);
        canvas.drawPath(mPath, mPaint);
        mPath = new Path();
        //繪製貝塞爾曲線
        mPath.cubicTo(100, 50, 200, 300, 400, 220);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

cubicTo

實例7:更改起點

@Override
     protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        //爲了增強效果對比,我們繪製出三個控制點之間對應的直線
        mPath.moveTo(200,100);
        mPath.lineTo(100,50);
        mPath.lineTo(200, 300);
        mPath.lineTo(400, 220);
        canvas.drawPath(mPath, mPaint);
        mPath = new Path();
        //繪製貝塞爾曲線
        mPath.moveTo(200,100);
        mPath.cubicTo(100, 50, 200, 300, 400, 220);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

moveToAndcubicTo

7、public void rQuadTo(float dx1, float dy1, float dx2, float dy2) 
方法同quadTo,主要不同是這裏的dx、dy表示的是座標的差值,類似上面的rlineTo,相對上一個點的dx、dy的計算後的終點。但是注意此時的dx、dy都是相對於起點,即二者的起點都是相同的,(dx2,dy2)不是相對於(dx1,dy1)。
實例8:

@Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        //爲了增強效果對比,我們繪製出三個控制點之間對應的直線
        mPath.rLineTo(100,100);
        mPath.lineTo(400, 220);
        canvas.drawPath(mPath, mPaint);
        mPath = new Path();
        //繪製貝塞爾曲線
        mPath.rQuadTo(100, 100,400, 220);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

效果圖: 
rquadTo 
最終的終點是(400,220),所以也印證了dx2、dy2與dx1、dy1有相同的起點。

8、public void rCubicTo(float x1, float y1, float x2, float y2, 
float x3, float y3)效果與上相同,就不演示了。

9、public void arcTo(RectF oval, float startAngle, float sweepAngle)
用於繪製圓弧。
public void addRect(float left, float top, float right, float bottom, Direction dir)添加矩形
實例9:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        RectF rectF = new RectF(100,100,300,300);
        mPath.addRect(rectF, Path.Direction.CW);
        mPath.addArc(rectF,0,360);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

效果圖: 
arc

其它幾個方法類似。

10、 public void addOval(RectF oval, Direction dir)
添加一個閉環的圓環路徑。
實例10:

@Override
     protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        RectF rectF = new RectF(100,100,400,300);
        mPath.addRect(rectF, Path.Direction.CW);
        mPath.addOval(rectF,Path.Direction.CW);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

效果圖: 
oval

11、public void addCircle(float x, float y, float radius, Direction dir) 
添加一個圓形路徑。
實例11:

@Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.addCircle(200,200,100,Path.Direction.CW);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

效果圖: 
cicle

12、public void addRoundRect(RectF rect, float rx, float ry, Direction dir)
添加圓角矩形路徑。

  • @param rx The x-radius of the rounded corners on the round-rectangle
  • @param ry The y-radius of the rounded corners on the round-rectangle
  • @param dir The direction to wind the round-rectangle’s contour

實例12:

@Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        RectF rectF = new RectF(100,100,400,300);
        mPath.addRoundRect(rectF,20,20, Path.Direction.CW);
        canvas.drawPath(mPath,mPaint);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

效果圖: 
RoundrectF

13、public void offset(float dx, float dy, Path dst)
public void offset(float dx, float dy)
通過dx、dy進行移動path,如果dst爲null,則修改原路徑,即src

14、 public void reset(),清空path路徑中的信息。
15、 public void rewind(),rewind當前path,清除掉所有直線,曲線,但是保留它內部的數據結構,以便更好的重新使用

補充:
1、Path.Direction 
用來指定添加到path中的模型(比如方形,橢圓)的閉合方向,有兩個值

  • CCW 表示逆時針
  • CW 表示順時針

2、FillType表示填充模式,它的填充模式和Paint的不同,它有四個枚舉值。Inverse就是去反之意。

  • FillType.WINDING,默認值,當兩個圖形香蕉,正常相交情況顯示
  • FillType.EVEN_ODD,取path所在並不相交的區域
  • FillType.INVERSE_WINDING,取path的外部區域
  • FillType.INVERSE_EVEN_ODD:取path外部和相交區域

實例:

 @Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPath.addRect(100, 100, 300, 300, Path.Direction.CW);
        mPath.addCircle(300, 300, 100, Path.Direction.CW);
        mPath.setFillType(Path.FillType.WINDING);
        canvas.drawPath(mPath,mPaint);
    } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(1)FillType.WINDING 
winding 
(2)FillType.EVEN_ODD 
EVEN_ODD 
(3)INVERSE_EVEN_ODD 
FillType.INVERSE_EVEN_ODD 
(4)FillType.INVERSE_WINDING 
FillType.INVERSE_WINDING

至此,所有的Path的使用基本介紹完畢。下面我們繼續我們前進的腳步,學習與Path對象息息相關的一個對象——PathMeasure。見名思意,該類的功能就是用來測量Path對象的。

PathMeasure

構造方法

(1)、無參構造方法

public PathMeasure() {
        mPath = null;
        native_instance = native_create(0, false);
    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

(2)有參構造方法

public PathMeasure(Path path, boolean forceClosed) {
        // The native implementation does not copy the path, prevent it from being GC'd
        mPath = path;
        native_instance = native_create(path != null ? path.ni() : 0,
                                        forceClosed);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一般方法介紹

(1)、public void setPath(Path path, boolean forceClosed) ,設置測量的path對象
(2)、public float getLength() ,測量path的長度
(3)、 public boolean getPosTan(float distance, float pos[], float tan[]),根據distance獲取對應的點座標
(4)、public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo),返回指定distance之間的path段。
注意:無論多複雜,PathMeasure也是將所有path中的路徑看成一個直線,取位置,然後計算出對應的座標。

下面我們做個小demo來練習下上面的知識點。 
效果圖: 
result

最後貼上源碼:

    /**
     * Created by dsw on 2015/10/5.
     */
    public class MyLine extends View {
    private Paint mPaint;
    private Path mPath;
    private PathMeasure pathMeasure;
    //path路徑的總長度
    private int mLenght;
    //當前路徑的長度
    private int mCurrentPath;
    private float[] currentPosition;
    private Bitmap bitmap;
    private float pointX[] = new float[5];
    private float pointY[] = new float[5];
    public MyLine(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPath = new Path();
        currentPosition = new float[2];
        bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.star);
        mPaint.setColor(Color.parseColor("#ff0000"));
        mPaint.setStyle(Paint.Style.STROKE);
        //初始化我們的五角星五個點座標
        pointX[0] = 113.5f;pointY[0] =150f;
        pointX[1] = 286.5f;pointY[1] = 150f;
        pointX[2] = 150f;pointY[2] = 286.5f;
        pointX[3] = 200f;pointY[3] = 100f;
        pointX[4] = 250f;pointY[4] = 286.5f;
        //將mPath移動到第一個點作爲起點
        mPath.moveTo(pointX[0], pointY[0]);
        for(int i=1;i<5;i++) {
            mPath.lineTo(pointX[i],pointY[i]);
        }
        mPath.lineTo(pointX[0],pointY[0]);
        pathMeasure = new PathMeasure();
        pathMeasure.setPath(mPath,true);
        mLenght = (int) pathMeasure.getLength();
    }

    @Override
       protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
        if(mCurrentPath == 0 && currentPosition[0]==0 && currentPosition[1]==0){
            startAnimator();
        }else{
            canvas.drawBitmap(bitmap,currentPosition[0]-bitmap.getWidth()/2,
                    currentPosition[1]-bitmap.getHeight()/2,mPaint);
        }
    }

    /**
     * 計算每次的位置
     */
    private void startAnimator(){
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mLenght);
        valueAnimator.setDuration(5000);
        valueAnimator.setRepeatCount(-1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurrentPath = (int) animation.getAnimatedValue();
                pathMeasure.getPosTan(mCurrentPath, currentPosition, null);
                invalidate();
            }
        });
        valueAnimator.start();
    }
    }轉載:http://blog.csdn.net/mr_dsw/article/details/48931515
發佈了74 篇原創文章 · 獲贊 16 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章