1. 程式人生 > >自定義控件之路徑

自定義控件之路徑

change swe 設定 pro 方向 蜘蛛 區域 inverse contex

在Android 中Path類中代表路徑

在canves中繪制路徑的方法如下

drawPath(Path path, Paint paint)

直接路徑

 moveTo(float x1, float y1) 

x1,y1是直線的起始點

lineTo(float x2, float y2)

x2,y2代表直線的終點

close()

如果畫了幾條直線沒有形成閉環,那麽這個函數會讓路徑首尾點連接,形成閉環.

繪制三角形示例

        Path path = new Path();
        path.moveTo(10,10);//
設定起始點 path.lineTo(10,100);//畫第一條直線 path.lineTo(100,200);//畫第二條直線 path.close(); //閉環 canvas.drawPath(path,paint);

弧形路徑

public void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) 
public void arcTo(RectF oval, float startAngle, float sweepAngle)
public void arcTo(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo)

說明:

  startAngle 弧開始的角度,以X軸正方向為0度

  sweepAngle 弧持續的角度

  forceMoveTo 是否強制將弧的起始點作為繪制的起始位置

     
     RectF rectF = new RectF(100, 10, 200, 100);
     Path path = new Path(); path.moveTo(
10,10); path.arcTo(rectF, 0, 90); canvas.drawPath(path, paint);


addXXX系列函數

代表直接往path中添加曲線,不必考慮連貫性

        RectF rectF = new RectF(100, 10, 200, 100);
        Path path = new Path();
        path.moveTo(10,10);
        path.lineTo(10,50);
        path.addArc(rectF, 0, 90);
        canvas.drawPath(path, paint);

添加矩形路徑

 public void addRect(RectF rect, Path.Direction dir) 
 public void addRect(float left, float top, float right, float bottom, Path.Direction dir)

Path.Direction參數有二個值:

  Path.Direction.CCW指創建逆時針方向的矩形路徑

  Path.Direction.CW指創建順時針方向的矩形路徑

註意:路徑的大小只與生成路徑的矩形大小有關,與生成方向無關.生成方向區別在於根據生成方向的排字

示例代碼:

/**
         * 依據路徑方向布局文字
         */
        //先創建兩個大小一樣的路徑
        //第一個逆向生成
        Path CCWRectpath = new Path();
        RectF rect1 =  new RectF(50, 50, 240, 200);
        CCWRectpath.addRect(rect1, Path.Direction.CCW);

        //第二個順向生成
        Path CWRectpath = new Path();
        RectF rect2 =  new RectF(290, 50, 480, 200);
        CWRectpath.addRect(rect2, Path.Direction.CW);

        //先畫出這兩個路徑
        canvas.drawPath(CCWRectpath, paint);
        canvas.drawPath(CWRectpath, paint);

        //依據路徑寫出文字
        String text="苦心人天不負,有誌者事竟成";
        paint.setColor(Color.GREEN);
        paint.setTextSize(35);
        canvas.drawTextOnPath(text, CCWRectpath, 0, 18, paint);//逆時針生成
        canvas.drawTextOnPath(text, CWRectpath, 0, 18, paint);//順時針生成

效果:

技術分享圖片

添加圓角矩形路徑

 public void addRoundRect(RectF rect, float rx, float ry, Path.Direction dir)
 public void addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir)
 public void addRoundRect(RectF rect, float[] radii, Path.Direction dir) 
 public void addRoundRect(float left, float top, float right, float bottom, float[] radii, Path.Direction dir) 
        /**
         * 圓角矩形路徑
         */
        Path path = new Path();
        RectF rect1 =  new RectF(50, 50, 240, 200);
        path.addRoundRect(rect1, 10, 15 , Path.Direction.CCW);

        RectF rect2 =  new RectF(290, 50, 480, 200);
        float radii[] ={10,15,20,25,30,35,40,45};
        path.addRoundRect(rect2, radii, Path.Direction.CCW);

        canvas.drawPath(path, paint);

添加圓形路徑

 public void addCircle(float x, float y, float radius, Path.Direction dir)
     Path path = new Path();
        path.addCircle(100, 100, 50, Path.Direction.CCW);
        canvas.drawPath(path, paint);

添加橢圓路徑

 public void addOval(RectF oval, Path.Direction dir)
 public void addOval(float left, float top, float right, float bottom, Path.Direction dir)
       /**
         * 橢圓路徑
         */
        Path path = new Path();
        RectF rect = new RectF(10, 10, 200, 100);
        path.addOval(rect, Path.Direction.CCW);
        canvas.drawPath(path, paint);

添加弧形路徑

 public void addArc(RectF oval, float startAngle, float sweepAngle) 
 public void addArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle)
      /**
         * 添加弧線路徑
         */
        Path path = new Path();
        RectF rect = new RectF(10, 10, 100, 50);
        path.addArc(rect, 0, 100);
        canvas.drawPath(path, paint);

path填充模式

有4個值:

  path.setFillType(Path.FillType.WINDING); //默認值,.當二個圖形相交時,取相交部分
  path.setFillType(Path.FillType.EVEN_ODD);//取path所在並不相交的區域
  path.setFillType(Path.FillType.INVERSE_WINDING);//取path的外部區域
  path.setFillType(Path.FillType.INVERSE_EVEN_ODD);//取path的外部和相交區域

示例效果:

        paint.setStyle(Paint.Style.FILL); // 填充樣式//Paint.Style.FILL沒有描邊的實心圓  Paint.Style.FILL_AND_STROKE 有描邊的實心圓 Paint.Style.STROKE  空心圓環
        paint.setColor(Color.RED);
        Path path = new Path();
        path.addRect(100,100,300,300,Path.Direction.CW);
        path.addCircle(300, 300, 100, Path.Direction.CW);
//        path.setFillType(Path.FillType.WINDING); //默認值,.當二個圖形相交時,取相交部分
//        path.setFillType(Path.FillType.EVEN_ODD);//取path所在並不相交的區域
//        path.setFillType(Path.FillType.INVERSE_WINDING);//取path的外部區域
        path.setFillType(Path.FillType.INVERSE_EVEN_ODD);//取path的外部和相交區域
        canvas.drawPath(path, paint);
    }

效果如下

技術分享圖片

WINDING

技術分享圖片

EVEN_ODD

技術分享圖片

INVERSE_WINDING

技術分享圖片

INVERSE_EVEN_ODD


重置路徑

        path.rewind();
        path.reset();

rewind函數的會清除Filltype以及所有直線,曲線點的數據,但是會保留數據結構

reset函數類似於新建一個路徑對象,它的所有數據空間都會被回收並重新,但不會清除FillType

從整體上來看rewind函數不會清除內存,但會清除FillType,而reset函數則會清除內存,但不會清除FillType

示例代碼:

public class BasisView extends View {

    private int count = 6;
    private float radius;//網格最大半徑
    private int centerX;//中心X
    private int centerY;//中心Y
    private Paint radarPaint,valuePaint;
    //計算出每個夾角的度數
    private float angle = (float) (Math.PI*2/count);
    //數據
    private double[] data={2,5,1,6,4,5};
    //最大值
    private float maxValue=6;
    public BasisView(Context context) {
        super(context);
        init();
    }

    public BasisView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BasisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        radarPaint = new Paint();
        radarPaint.setStyle(Paint.Style.STROKE);
        radarPaint.setColor(Color.GREEN);
        valuePaint = new Paint();
        valuePaint.setColor(Color.BLUE);
        valuePaint.setStyle(Paint.Style.FILL);
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        radius = Math.min(h, w)/2*0.9f;
        //中心坐標
        centerX = w/2;
        centerY = h/2;
        postInvalidate();
        super.onSizeChanged(w, h, oldw, oldh);
    }

    /**
     * 繪制正多邊形
     */
    private void drawPolygon(Canvas canvas){
        Path path = new Path();
        float r = radius/(count);//r是蜘蛛絲之間的間距
        for(int i=1;i<=count;i++){//中心點不用繪制
            float curR = r*i;//當前半徑
            path.reset();
            for(int j=0;j<count;j++){
                if(j==0){
                    path.moveTo(centerX+curR,centerY);
                }else{
                    //根據半徑,計算出蜘蛛絲上每個點的坐標
                    float x = (float) (centerX+curR*Math.cos(angle*j));
                    float y = (float) (centerY+curR*Math.sin(angle*j));
                    path.lineTo(x,y);
                }
            }
            path.close();//閉合路徑
            canvas.drawPath(path, radarPaint);
        }
    }

    /**
     * 繪制直線
     */
    private void drawLines(Canvas canvas){
        Path path = new Path();
        for(int i=0;i<count;i++){
            path.reset();
            path.moveTo(centerX, centerY);
            float x = (float) (centerX+radius*Math.cos(angle*i));
            float y = (float) (centerY+radius*Math.sin(angle*i));
            path.lineTo(x, y);
            canvas.drawPath(path, radarPaint);
        }
    }

    /**
     * 繪制區域
     * @param canvas
     */
    private void drawRegion(Canvas canvas){
        Path path = new Path();
        valuePaint.setAlpha(127);
        for(int i=0;i<count;i++){
            double percent = data[i]/maxValue;
            float x = (float) (centerX+radius*Math.cos(angle*i)*percent);
            float y = (float) (centerY+radius*Math.sin(angle*i)*percent);
            if(i==0){
                path.moveTo(x, centerY);
            }else{
                path.lineTo(x,y);
            }
            //繪制小圓點
            canvas.drawCircle(x,y,10,valuePaint);
        }
        //繪制填充區域
        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, valuePaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawPolygon(canvas);
        drawLines(canvas);
        drawRegion(canvas);
    }


}

效果圖

技術分享圖片

自定義控件之路徑