第六章 一张白纸好作画—Canvas画布(4)

6.4.4路径android.graphics.Path

当我们的需求是一个不规则的图形的时候,Canvas的drawRect等方法就不行了,这里就要用到drawPath(Path path, Paint paint)方法来按路径绘画一个形状。Canvas还有一个方法clipPath(Path path)。这个方法用于按照设计的路径来设置Canvas中的有效区域。

下面我们就介绍下路径类,它是一个多个点和图形的集合。

Path的构造方法比较简单,如下:

Path path1 = new Path();  //构造方法 

 

下面我们画一个封闭的原型路径,我们使用Path类的addCircle方法。

path1.addCircle(10,10,50,Direction.CW);

 

解释下此方法:

voidaddCircle(float x, float y, float radius, Direction dir)

参数 x是x轴水平位置;参数y是y轴垂直位置;参数radius是圆形的半径;参数dir是绘制的方向,CW为顺时针方向,而CCW是逆时针方向。

同样我们也可以自由的添加一些点和线,而组成一个三角形。

Path path2 = new Path();

// 将路径的起始点移到90,330

path2.moveTo(90, 330);

// 从90,330画一条直线到150,330

path2.lineTo(150,330);

// 从150,330画一条直线到120,270

path2.lineTo(120,270);

// 关闭当前的轮廓。这样就形成一个三角形了

path2.close();

 

结合Canvas类中的绘制方法drawPath()和drawTextOnPath(),我们可以在onDraw()中加入如下代码。

// 这里pathPaint为路径的画笔的颜色

canvas.drawPath(path1, pathPaint);

// 将文字绘制到路径中去

canvas.drawTextOnPath("Android", path2,0,15, textPaint);

 

下面,我们的onDraw()方法中演示了如何绘制路径。

@Override 

protected void onDraw(Canvas canvas) { 

Paint pathPaint =new Paint(); 

Paint textPaint =new Paint(); 

// 路径的画刷为红色

pathPaint.setColor(Color.Red); 

// 设置paint的style为FILL:实心

pathPaint.setStyle(Paint.Style.FILL);

// 路径上的文字为蓝色 

textPaint.setColor(Color.Blue);

Path path1 = new Path();

Path path2 = new Path(); 

 

// 省略部分代码

 

canvas.drawPath(path1, pathPaint); 

// 在路径上绘制文字

canvas.drawTextOnPath("Android", path2,0,15, textPaint); 

 

解释下方法:

voiddrawTextOnPath (String text, Path path, float hOffset, float vOffset, Paintpaint) 

参数text,为需要在路径上绘制的文字内容;参数path,将文字绘制到哪个路径;参数hOffset,距离路径开始的距离;参数vOffset,离路径的上下高度,该参数类型为float浮点型,除了精度为8位小数外,可以为正或负,当为正时文字在路径的圈里面,为负时在路径的圈外面;参数paint,最后仍然是一个Paint对象用于制定Text本文的颜色、字体、大小等属性。

有关路径类常用的其它方法如表6-5所示。

方法

返回值

说明

addArc(RectF oval, float startAngle, float sweepAngle)

void   

为路径添加一个多边形

addCircle(float x, float y, float radius, Path.Direction dir)

void   

给路径添加圆圈

addOval(RectF oval, Path.Direction dir)

void   

添加椭圆形

addRect(RectF rect, Path.Direction dir)

void   

添加一个区域

addRoundRect(RectF rect, float[] radii, Path.Direction dir)

void   

添加一个圆角区域

isEmpty()

boolean 

判断路径是否为空

transform(Matrix matrix)

void   

应用矩阵变换

transform(Matrix matrix, Path dst)

void   

应用矩阵变换并将结果放到新的路径中,即第二个参数。

表6-5 Path类常用的其它方法

 

6.4.5路径的高级效果android.graphics.PathEffect

一条直线是否太单调了,下面我们来看看路径的高级效果,如图6-2所示。是不是很炫,这些效果其实都是使用PathEffect类实现的。

图6-2 路径的高级效果

 

PathEffect对于绘制Path基本图形特别有用,它可以应用到任何Paint中从而影响线条绘制的方式。使用PathEffect,可以改变一个形状的边角的外观并且控制轮廓的外表。SDK附带的ApiDemos(com.example.android.apis.graphics.PathEffects.java)示例给出了如何应用每一种效果的指导说明。图6-2就是ApiDemos中的PathEffects的效果图。

 

Android包含了多个PathEffect,包括:

1)CornerPathEffect  可以使用圆角来代替尖锐的角从而对基本图形的形状尖锐的边角进行平滑。

2)DashPathEffect  可以使用DashPathEffect来创建一个虚线的轮廓(短横线/小圆点),而不是使用实线。你还可以指定任意的虚/实线段的重复模式。

3)DiscretePathEffect  与DashPathEffect相似,但是添加了随机性。当绘制它的时候,需要指定每一段的长度和与原始路径的偏离度。

4)PathDashPathEffect  这种效果可以定义一个新的形状(路径)并将其用作原始路径的轮廓标记。

复杂的效果可以在一个Paint中使用多个Path Effect组合而成的一个PathEffect。

5)SumPathEffect  顺序地在一条路径中添加两种效果,这样每一种效果都可以应用到原始路径中,并且两种效果结合起来。SumPathEffect (first, second) = first(path) + second(path)

6)ComposePathEffect  组合两种效果,结果为先使用第一种效果,然后在这种效果的基础上应用第二种效果。ComposePathEffect (outer ,inner)= Outer(inner(path))。

7)DiscretePathEffect 将路径划分成指定长度的线段,然后把每条线段随机偏移原来的位置。

对象形状的PathEffect的改变会影响到形状的区域。这就能够保证应用到相同形状的填充效果将会绘制到新的边界中。

上面效果图的核心代码如下:

// phase 指定的是虚线上虚实偏移,每次加1,相当于交换虚处和实处的位置。

// 这样通过不停的刷新就可以达到虚实不断变换给人以动画的效果。

private static void makeEffects(PathEffect[] e, float phase) {

e[0] = null;

e[1] = new CornerPathEffect(10);

e[2] = new DashPathEffect(new float[] {10, 5, 5, 5}, phase);

e[3] = new PathDashPathEffect(makePathDash(), 12, phase,

                    PathDashPathEffect.Style.TRANSLATE);

e[4] = new PathDashPathEffect(makePathDash(), 12, phase,

                    PathDashPathEffect.Style.ROTATE);

e[5] = new PathDashPathEffect(makePathDash(), 12, phase,

                    PathDashPathEffect.Style.MORPH);

e[6] = new ComposePathEffect(e[2], e[1]);

e[7] = new SumPathEffect(e[2], e[1]);

e[8] = new ComposePathEffect(e[5], e[1]);

e[9] = new SumPathEffect(e[5], e[1]);

}

// 制造一个形状,PathDashPathEffect显示的单位形状

private static Path makePathDash() {

Path p = new Path();

p.moveTo(4, 0);

p.lineTo(0, -4);

p.lineTo(8, -4);

p.lineTo(12, 0);

p.lineTo(8, 4);

p.lineTo(0, 4);

return p;

}

6.4.6点类 android.graphics.Point和android.graphics.PointF

看过了Canvas画出的线条,那么我们来看看组成线条的基础,点(Point类)。

Point类有两个属性,分别是:X 坐标和 y 坐标。

构造函数有三种。

Point() //构造一个点

Point(int x,int y) //传入x和y坐标构造一个点

Point(Point p) //传入一个Point对象构造一个点

 

主要方法如表6-6所示。

方法

返回值

说明

set(x,y)

void

重新设定一下 x,y 的坐标

offset(int dx,int dy)

void

给坐标一个补偿值,值可以使正的也可以是负的

negate()

void

否定坐标值

表6-6 Point类常用的方法

 

Point类和android.graphics.PointF类似,不同点是前者坐标值的类型是 int 型,而后者的坐标值是float 型。

除此之外 PointF 类多加了 几个方法,比如:

public final float length();//返回(0,0)点到该点的距离。

public static float length(float x,float y);//返回(0,0)点到(x,y) 点的距离。

 

经验分享:

说到坐标点,那么我们就不得不说下手机屏幕的坐标系,手机的坐标系和一般的物理坐标系不同,手机屏幕坐标系的原点(0,0)在屏幕的左上角,沿左沿边和上沿边,x,y数值依次增加。如下图6-3所示。

 

图6-3手机坐标点示意图

 

6.4.7形状类android.graphics.Rect和android.graphics.RectF

矩形,绘图上比较常用的几种形状之一。RectF这个类包含一个矩形的四个单精度浮点坐标。矩形通过上、下、左、右4个边的坐标来表示一个矩形。这些坐标值属性可以被直接访问,用width()和height()方法可以获取矩形的宽和高。

RectF一共有四个构造方法.

RectF() //构造一个无参的矩形

RectF(float left,float top,float right,float bottom) //构造一个指定了4个参数的矩形

RectF(RectF r) //根据指定的RectF对象来构造一个RectF对象(复制一个Rect F)

RectF(Rect r) //根据给定的Rect对象来构造一个RectF对象

 

RectF提供了很多方法,下面介绍几个方法,如表6-7所示。

方法

返回值

说明

contain(RectF r)

boolean

判断一个点或矩形是否在此矩形内,如果在这个矩形内或者和这个矩形等价则返回true

offset(float dx, float dy)

void

平移dx,dy距离

offsetTo(float newLeft, float newTop)

void

平移到新的位置

inset(float dx, float dy)

void

缩小2*dx,2*dy

表6-7 RectF类常用的方法

 

经验分享:

Android.graphics.Rect类, 这个类同android.graphics.RectF很相似,不同的地方是Rect类的坐标是用整型表示的,而RectF的坐标是用单精度浮点型表示的。

获取Matrix中的X的缩放比例:

public void getValues(float[] values);

// 数组values是一个size>9的数组,values [Matrix.MSCALE_X]就为缩放比例。其他参数也在其中如:Matrix。

public static final int MSCALE_X = 0;

public static final int MSKEW_X  = 1;

public static final int MTRANS_X = 2;

public static final int MSKEW_Y  = 3;

public static final int MSCALE_Y = 4;

public static final int MTRANS_Y = 5;

public static final int MPERSP_0 = 6;

public static final int MPERSP_1 = 7;

public static final int MPERSP_2 = 8;

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页