安卓自定义View进阶-Canvas之画布操作

参考文章:
GcsSloop
启舰

上一篇Canvas之绘制基本图形中我们了解了如何使用Canvas绘制基本图形,本次了解一些基本的画布操作。

一.Canvas的常用操作速查表

这里写图片描述

二.Canvas基本操作

为什么要有画布操作?

画布操作可以帮助我们用更加容易理解的方式制作图形。

例如: 从坐标原点为起点,绘制一个长度为20dp,与水平线夹角为30度的线段怎么做?

按照我们通常的想法(被常年训练出来的数学思维),就是先使用三角函数计算出线段结束点的坐标,然后调用drawLine即可。

然而这是否是被固有思维禁锢了?

假设我们先绘制一个长度为20dp的水平线,然后将这条水平线旋转30度,则最终看起来效果是相同的,而且不用进行三角函数计算,这样是否更加简单了一点呢?

注意:所有的画布操作都只影响后续的绘制,对之前已经绘制过的内容没有影响

例如下面的操作画两个矩形,两个矩形能重合吗?

这里写图片描述
实际效果是这样的:
这里写图片描述

这种情况有点难以理解,明明将画布平移了,为什么之前画的矩形没有平移

这是由于屏幕显示与Canvas根本不是一个概念!Canvas是一个很虚幻的概念,相当于一个透明图层(用过PS的同学应该都知道),每次Canvas画图时(即调用Draw系列函数),都会产生一个透明图层,然后在这个图层上画图,画完之后覆盖在屏幕上显示。所以上面的两个结果是由下面几个步骤形成的:

1、调用canvas.drawRect(rect1, paint);时,产生一个Canvas透明图层,由于当时还没有对坐标系平移,所以坐标原点是(0,0);再在系统在Canvas上画好之后,覆盖到屏幕上显示出来,过程如下图:
这里写图片描述

2、然后再第二次调用canvas.drawRect(rect1, paint);时,又会重新产生一个全新的Canvas画布,但此时画布坐标已经改变了,即向右和向下分别移动了100像素,所以此时的绘图方式为:(合成视图,从上往下看的合成方式)
这里写图片描述

下面对上面的知识做一下总结:

1、每次调用canvas.drawXXXX系列函数来绘图进,都会产生一个全新的Canvas画布。
2、如果在DrawXXX前,调用平移、旋转等函数来对Canvas进行了操作,那么这个操作是不可逆的!每次产生的画布的最新位置都是这些操作后的位置。(关于Save()、Restore()的画布可逆问题的后面再讲)
3、在Canvas与屏幕合成时,超出屏幕范围的图像是不会显示出来的。

1、位移(translate)

translate是坐标系的移动,可以为图形绘制选择一个合适的坐标系。 请注意,位移是基于当前位置移动,而不是每次基于屏幕左上角的(0,0)点移动(上面代码和图片已经说了平移操作)

2、缩放(scale))

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

这两个方法中前两个参数是相同的分别为x轴和y轴的缩放比例。而第二种方法比前一种多了两个参数,用来控制缩放中心位置的。

缩放比例(sx,sy)取值范围详解:

这里写图片描述

这里写图片描述

这里写图片描述

我们用第二种方法改变缩放中心的位置
>

这里写图片描述

这里写图片描述

我们可以将缩放比例改成负数
>

这里写图片描述

这里写图片描述

和位移(translate)一样,缩放也是可以叠加的。
>

这里写图片描述

这里写图片描述

调用两次缩放则 x轴实际缩放为0.5x0.5=0.25 y轴实际缩放为0.5x0.5=0.25

小案例

这里写图片描述

这里写图片描述

3、旋转(translate)

旋转提供了两种方法:
public void rotate (float degrees)
public final void rotate (float degrees, float px, float py)

第一种方式:

这里写图片描述

这里写图片描述

改变旋转中心位置:

这里写图片描述

这里写图片描述

旋转也是可叠加的
总共旋转180+20=200度

这里写图片描述

这里写图片描述

小案例:

这里写图片描述

这里写图片描述

4、错切(skew)

错切只提供了一种方法:
public void skew (float sx, float sy)

参数含义:

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

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

这里写图片描述

这里写图片描述

5、裁剪画布(clip)

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

boolean clipPath(Path path)
boolean clipPath(Path path, Region.Op op)
boolean clipRect(Rect rect, Region.Op op)
boolean clipRect(RectF rect, Region.Op op)
boolean clipRect(int left, int top, int right, int bottom)
boolean clipRect(float left, float top, float right, float bottom)
boolean clipRect(RectF rect)
boolean clipRect(float left, float top, float right, float bottom, Region.Op op)
boolean clipRect(Rect rect)
boolean clipRegion(Region region)
boolean clipRegion(Region region, Region.Op op)

拿ClipRect()来稍微一讲。
>

这里写图片描述

这里写图片描述

6、画布的保存与恢复(save()、restore())

前面我们讲的所有对画布的操作都是不可逆的,这会造成很多麻烦,比如,我们为了实现一些效果不得不对画布进行操作,但操作完了,画布状态也改变了,这会严重影响到后面的画图操作。如果我们能对画布的大小和状态(旋转角度、扭曲等)进行实时保存和恢复就最好了。
这小节就给大家讲讲画布的保存与恢复相关的函数——Save()、Restore()。

int save ()
void restore()

Save():每次调用Save()函数,都会把当前的画布的状态进行保存,然后放入特定的栈中;

restore():每当调用Restore()函数,就会把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布,并在这个画布上做画。

为了更清晰的显示这两个函数的作用,下面举个例子:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

最终会是绿色

下面我通过一个多次利用Save()、Restore()来讲述有关保存Canvas画布状态的栈的概念:代码如下:

这里写图片描述

这里写图片描述

在这段代码中,总共调用了四次Save操作。上面提到过,每调用一次Save()操作就会将当前的画布状态保存到栈中,所以这四次Save()所保存的状态的栈的状态如下:

这里写图片描述

注意在,第四次Save()之后,我们还对画布进行了canvas.clipRect(new Rect(400, 400, 500, 500));操作,并将当前画布画成白色背景。也就是上图中最小块的白色部分,是最后的当前的画布。

如果,现在使用Restor(),会怎样呢,会把栈顶的画布取出来,当做当前画布的画图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android自定义View中的Canvas是一个绘图容器,可以在其上进行2D绘图操作。通过Canvas,我们可以绘制图形、文字、位图等。 要在自定义View中使用Canvas,需要重写View的onDraw()方法,并在该方法中获取Canvas实例,然后进行绘制操作。 下面是一个简单的示例代码,展示如何在自定义View中使用Canvas绘制一个矩形: ```java public class MyCustomView extends View { public MyCustomView(Context context) { super(context); } public MyCustomView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(100, 100, 300, 300, paint); } } ``` 在这个示例中,我们创建了一个名为MyCustomView自定义View,并重写了它的onDraw()方法。在该方法中,我们首先创建了一个Paint对象,设置了画笔的颜色为红色,并指定绘制的样式为填充。然后,使用Canvas的drawRect()方法绘制一个矩形,坐标为(100, 100)到(300, 300)。 当我们在布局文件中使用这个自定义View时,它会自动调用onDraw()方法进行绘制,从而在屏幕上显示出红色矩形。 需要注意的是,Canvas提供了许多其他绘制方法,如drawCircle()、drawText()等,可以根据需求选择合适的方法进行绘制操作。此外,还可以通过设置Paint对象的属性来实现不同的绘制效果,如线条宽度、字体大小等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值