自定义控件之路径
在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); } }
效果图