自定义控件之绘图篇(四):canvas变换与操作

飞来科技  发布时间:2019-08-08 12:04:15

本文关键词:画图板 透明背景

洞洞板 画图_画图板 透明背景_透明箭头背景psd素材

《Android自定义控件三部曲文章索引》:

canvas中有一个函数translate()是用于实现画板平移的,油画的原状是以左上角为原点,向左是X轴正方向,往下是Y轴正方向,如下图所示

translate函数同样实现的相当于平移坐标系,即平移坐标系的原点的位置。translate()变量的蓝本如下:

void translate(float dx, float dy)

参数说明:

float dx:水平方向平移的距离,负数指向正方向(向右)平移的量,正数为向负方向(向左)平移的量

flaot dy:垂直方向平移的距离,负数指向正方向(上行)平移的量,正数为向负方向(向上)平移的量

protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	super.onDraw(canvas);
	
	//translate  平移,即改变坐标系原点位置
	
	Paint paint = new Paint();
	paint.setColor(Color.GREEN);
	paint.setStyle(Style.FILL);
	
//	canvas.translate(100, 100);
	Rect rect1 = new Rect(0,0,400,220);
	canvas.drawRect(rect1, paint);
}
1、下面这段源码,先把canvas.translate(100, 100);注释掉,看原来矩形的位置,然后打开注释,看平移后的位置,对比如下图:

未平移 平移后

很多婊贝一直以为显示所画东西的改屏幕就是Canvas,当然这是一个非常错误的理解画图板 透明背景,譬如上面我们这段源码:

这段源码中,同一个矩形,在画板平移前画一次,平移后再画一次,你们会感到结果会怎么?

protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	super.onDraw(canvas);
	
	//构造两个画笔,一个红色,一个绿色
	Paint paint_green = generatePaint(Color.GREEN, Style.STROKE, 3);
	Paint paint_red   = generatePaint(Color.RED, Style.STROKE, 3);
	
	//构造一个矩形
	Rect rect1 = new Rect(0,0,400,220);
	//在平移画布前用绿色画下边框
	canvas.drawRect(rect1, paint_green);
	
	//平移画布后,再用红色边框重新画下这个矩形
	canvas.translate(100, 100);
	canvas.drawRect(rect1, paint_red);
}
private Paint generatePaint(int color,Paint.Style style,int width)
{
	Paint paint = new Paint();
	paint.setColor(color);
	paint.setStyle(style);
	paint.setStrokeWidth(width);
	return paint;
}
代码分析:

这段源码中,对于同一个矩形,在平移画布前利用白色画下栅格边框,在平移后,再用红色画下栅格边框。大家是不是会感到这两个边框会重叠?实际结果是如此的。

从到这个结果你们可能会狠蛋疼,我第一次看到这个结果的时候蛋都碎一地了要。淡定……

这个结果的关键问题在于,为什么蓝色框并没有移动?

这是由于屏幕显示与Canvas根本不是一个概念!Canvas是一个很虚无的定义,相当于一个透明图层(用过PS的学生可能都明白),每次Canvas画图时(即读取Draw系列函数),就会造成一个透明图层,然后在这个图层上画图,画完以后覆盖在萤幕上表明。所以下面的两个结果是由上面几个步骤形成的:

1、读取canvas.drawRect(rect1, paint_green);时,形成一个Canvas透明图层,由于当年还没有对坐标系平移,但是坐标原点是(,);再在功能在Canvas上画好以后,覆盖到屏幕上表明出来,过程如下图:

洞洞板 画图_透明箭头背景psd素材_画图板 透明背景

2、然后再第二次调用canvas.drawRect(rect1, paint_red);时,又会再次形成一个全新的Canvas画布,但此时画布坐标已经改变了,即向右和向下分别移动了100像素,但是此时的作图方法为:(生成视图,从上往下看的生成方法)

上图展示了,下层的Canvas图层与上方的萤幕的生成过程,由于Canvas画布已经平移了100像素,但是在画图时是以新原点来形成视图的,然后合成到屏幕上,这就是我们下面最后见到的结果了。我们看见屏幕移动之后,有一部分超出了屏幕的范围,那超乎范围的影像显不表明呢,其实不表明了!也就是说,Canvas上还是能画上,但超出了屏幕的范围,是不会显示的。当然,我们这儿也没有超出显示范围,两框框而已。

上面对里面的常识做一下总结:

1、每次读取canvas.drawXXXX系列函数来绘图进,就会造成一个全新的Canvas画布。

2、因为在DrawXXX前,读取平移、摆动等变量来对Canvas进行了操作,所以这个操作是不可逆的!每次造成的画笔的最新位置都是这些操作后的位置。(关于Save()、Restore()的画笔可逆问题的中间再讲)

3、在Canvas与萤幕合成时,超乎屏幕范围的影像是不会显示出来的。

画布的摆动是默认是围绕坐标原点来旋转的,这儿容易造成幻觉画图板 透明背景,看起来觉得是网络旋转了,当然我们旋转的是油画,之后在此画布上画的东西显示出来的时候全部看起来都是旋转的。其实Roate函数有两个构造函数:

void rotate(float degrees)

void rotate (float degrees, float px, float py)

第一个构造函数直接输入旋转的度数,负数是顺时针旋转,正数指逆时针旋转,它的摆动中心点是原点(,)

第二个构造函数除了度数以外,还可以指定旋转的中心点座标(px,py)

上面以第一个构造函数为例,旋转一个矩形,先画出未旋转前的图例,然后再画出旋转后的图例;

protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	super.onDraw(canvas);
	
	Paint paint_green = generatePaint(Color.GREEN, Style.FILL, 5);
	Paint paint_red   = generatePaint(Color.RED, Style.STROKE, 5);
	
	Rect rect1 = new Rect(300,10,500,100);
	canvas.drawRect(rect1, paint_red); //画出原轮廓
	
	canvas.rotate(30);//顺时针旋转画布
	canvas.drawRect(rect1, paint_green);//画出旋转后的矩形
} 
效果图是如此的:

这个最终屏幕显示的构造过程是如此的:

下图显示的是第一次画图合成过程,此时仅仅调用canvas.drawRect(rect1, paint_red); 画出原轮廓

然后是先将Canvas正方向依原点旋转30度,然后再与下面的萤幕合成,最终显示出我们的复合作用。

透明箭头背景psd素材_洞洞板 画图_画图板 透明背景

有关Canvas与萤幕的生成关系我认为我早已讲的够具体了,中间的几个操作Canvas的变量,我就不再一一讲它的生成过程了。

public void scale (float sx, float sy)

public final void scale (float sx, float sy, float px, float py)

当然我也没搞清第二个构造函数是什么使用的,我就先讲讲第一个构造函数的取值吧

float sx:水平方向伸缩的比重,假设原坐标轴的比重为n,不变时为1,在变更的X轴密度为n*sx;所以,sx为整数为扩大,sx为小数为放大

float sy:垂直方向伸缩的比重,同时,整数为扩大,小数为放大

注意:这儿有X、Y轴的体积的变化,表明到图形上都会正好相同,譬如X轴缩小,所以表明的图例也会扩大。一样的。

protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	super.onDraw(canvas);
	
//	//scale 缩放坐标系密度
	Paint paint_green = generatePaint(Color.GREEN, Style.STROKE, 5);
	Paint paint_red   = generatePaint(Color.RED, Style.STROKE, 5);
	
	Rect rect1 = new Rect(10,10,200,100);
	canvas.drawRect(rect1, paint_green);
	
	canvas.scale(0.5f, 1);
	canvas.drawRect(rect1, paint_red);
} 

当然我认为译成斜切更恰当,在PS中的这个系统就差不多叫斜切。但这儿还是意译吧,你们都是这个小名。看下它的构造函数:

void skew (float sx, float sy)

参数说明:

float sx:将画笔在x方向上倾斜相应的视角,sx倾斜角度的tan值,

float sy:将画笔在y轴方向上倾斜相应的视角,sy为倾斜角度的tan值,

注意,这儿全是倾斜角度的tan值哦,譬如我们准备在X轴方向上倾斜60度,tan60=根号3,整数对应1.732

protected void onDraw(Canvas canvas) {
	// TODO Auto-generated method stub
	super.onDraw(canvas);
	
	//skew 扭曲
	Paint paint_green = generatePaint(Color.GREEN, Style.STROKE, 5);
	Paint paint_red   = generatePaint(Color.RED, Style.STROKE, 5);
	
	Rect rect1 = new Rect(10,10,200,100);
	canvas.drawRect(rect1, paint_green);
	canvas.skew(1.732f,0);//X轴倾斜60度,Y轴不变
	canvas.drawRect(rect1, paint_red);
} 

裁剪画布是借助Clip系列函数,通过与Rect、Path、Region取交、并、差等集合运算来获得最新的画笔大小。除了调用Save、Restore函数以外,这个操作是不可逆的,一但Canvas画布被裁剪,就不能再被恢复!

Clip系列函数如下:

booleanclipPath(Path path)

booleanclipPath(Path path, Region.Op op)

洞洞板 画图_画图板 透明背景_透明箭头背景psd素材

booleanclipRect(Rect rect, Region.Op op)

booleanclipRect(RectF rect, Region.Op op)

booleanclipRect(int left, int top, int right, int bottom)

booleanclipRect(float left, float top, float right, float bottom)

本文来自互联网,由机器人自动采编,文章内容不代表本站观点,请读者自行辨别信息真伪,如有发现不适内容,请及时联系站长处理。

相关阅读
江苏快三开奖结果