自定义控件之路径

Posted loaderman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义控件之路径相关的知识,希望对你有一定的参考价值。

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);
    }


}

效果图

技术分享图片

 

以上是关于自定义控件之路径的主要内容,如果未能解决你的问题,请参考以下文章

自定义控件三部曲之绘图篇——Path之贝赛尔曲线和手势轨迹水波纹效果

自定义控件三部曲之动画篇——联合动画的代码实现

android自定义控件之飞入飞出控件

Android 自定义控件之 日期选择控件

qt自定义控件样式在提升使用中不生效之坑

自定义控件三部曲之动画篇——联合动画的代码实现