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

6.4.8区域 android.graphics.Region与Region.Op

在Canvas的绘画时,我们可能碰到止需要显示半个矩形,或者显示一部分图片,那么我们就要用到Canvas的设置区域的方法,有clipRect(Rect rect,Region.Op op)、clipRegion(Region region)这两个方法。Region表示的是一个区域和Rect不同的是,它可以表示的一个不规则的样子,可以是椭圆、多边形等等,当然Region也可以表示一个矩形,而Rect仅仅是矩形。

同样Region的boolean contains(int x, int y) 成员可以判断一个点是否在该区域内。

Region.Op是多个区域叠加效果的参数。


public enum Op {

DIFFERENCE(0),//DIFFERENCE 第一个中不同于第二个的部分显示出来

INTERSECT(1),//INTERSECT 取两者交集,默认的方式

UNION(2),//UNION 取全集

XOR(3),//XOR 补集,就是全集的减去交集的剩余部分显示

REVERSE_DIFFERENCE(4),//第二个不同于第一个的部分显示

REPLACE(5);//REPLACE 显示第二个的

}

下面我们来解读下SDK中的ApiDemos(com.example.android.apis.graphics.Region.java)这个示例。效果图如图6-4所示。

图6-4 Region的示例

它主要是将两个Rect放在同一个Region中,根据不同的Region.Op来制作出的效果图,有颜色的区域为有效区,不同的颜色表示合并后产生的不同Rect。

核心代码如下:


// 定义两个Rect(矩形)

mRect1.set(10, 10, 100, 80);

mRect2.set(50, 50, 130, 110);

// 定义一个Region,用来保存两个Rect的集合

Region rgn = new Region();

// 将mRect1添加进Region中

rgn.set(mRect1);

// 将mRect2添加进Region中,注意这里的第二个参数,他就是要传进去得效果的标示,详细参见上面的Region.Op说明。

rgn.op(mRect2, op);

// Region的迭代器,可以讲一个Region分解成不同的Rect,通过iter.next(Rect r)方法来把每个矩形提取出来。

RegionIterator iter = new RegionIterator(rgn);

Rect r = new Rect ();

while (iter.next(r)) {

canvas.drawRect(r, mPaint);

}

6.4.9千姿百态矩阵变换 android.graphics.Matrix

对前面的基础知识有所了解后,我们就可以来看android.graphics.Matrix类,该类表示一个转换矩阵,它确定如何将一个坐标空间的点映射到另一个坐标空间。通过设置Matrix对象的属性并将其应用于Canvas对象或Bitmap对象,我们可以对该对象执行各种图形转换。这些转换函数包括平移(x和y重新定位)、旋转、缩放和倾斜,达到很炫的效果。

matrix 对象被视为具有如下内容的 3 x 3 的矩阵:

在传统的转换矩阵中,u、v和w属性具有其它功能。Matrix类只能在二维空间中操作,因此始终假定属性值u和v为0.0,属性值w为1.0。换句话说,矩阵的有效值如下:

您可以获取和设置 Matrix 对象的全部六个其它属性的值:a、b、c、d、tx 和 ty。

Matrix类支持四种主要的转换函数类型:平移、缩放、旋转和倾斜。对于这些函数中的三种,有特定的方法,如表6-8中所述。


方法


矩阵值


显示结果


说明


Translate(tx,ty)




平移(置换),

将图像向右移动tx像素,向下移动ty 像素。


scale(sx, sy)




缩放,

调整图像的大小,方法是将每个像素的位置在 x 轴方向上乘以sx并在 y 轴方向上乘以sy。


rotate(q)




旋转,

将图像旋转一个以弧度为单位的角度q。


Skew(skx, sky)




倾斜,

以平行于X轴或Y轴的方向逐渐滑动图像。skx 值充当乘数,控制沿x 轴滑动的距离;sky控制沿y轴滑动的距离。

表6-8 Matrix类支持的四种主要的转换函数

下面的代码简单的实现了图片的倒影镜像


Matrix mMatrix = new Matrix();

mMatrix.setScale(1.0f, -1.0f);

canvas.drawBitmap(mBitmap, mMatrix, null);

上述的四种操作的方法,每种操作方法都有三种接口setXX、preXX、postXX。setXX将使整个matrix的值为设置的值。preXX是将新的变换矩阵左乘原来的矩阵,而postXX是将新的变换矩阵右乘原来的变换矩阵。


经验分享:

在组合matrix中preTranslate、setTranslate、postTranslate是有很大区别的。抽象的说pre方法是向前“生长”,post方法是向后“生长”,下面还是通过2个例子来说明:

matrix.preScale(0.5f, 1);

matrix.preTranslate(10, 0);

matrix.postScale(0.7f, 1);

matrix.postTranslate(15, 0);

则坐标变换经过的4个变换过程依次是:

translate(10, 0) -> scale(0.5f, 1) -> scale(0.7f, 1) -> translate(15, 0),

所以对matrix方法的调用顺序是很重要的,不同的顺序往往会产生不同的变换效果。pre方法的调用顺序和post方法的互不影响,即以下的方法调用和前者在真实坐标变换顺序里是一致的。

matrix.postScale(0.7f, 1);

matrix.preScale(0.5f, 1);

matrix.preTranslate(10, 0);

matrix.postTranslate(15, 0);

而matrix的set方法则会对先前的pre和post操作进行刷除,而后再设置它的值,比如下列的方法调用:

matrix.preScale(0.5f, 1);

matrix.postTranslate(10, 0);

matrix.setScale(1, 0.6f);

matrix.postScale(0.7f, 1);

matrix.preTranslate(15, 0);

其坐标变换顺序是translate(15, 0) -> scale(1, 0.6f) -> scale(0.7f, 1).

另外可以注意这个方法Matrix.mapRect(RectF rect);对RectF矩形进行变换。

矩阵一般应用在变换view的时候,那么很多时候我们将需要将一些点或矩形,进行转换,Android的Matrix为我们提供了很方便的方法来进行计算。下面我们来看个例子:


float[] p1 = {1000f,100f};

float[] p2 = {1000f,100f};

// 下面是一个正向的过程

// 原始变换矩阵

Matrix m1 = new Matrix();

// m1的逆矩阵

Matrix m2 = new Matrix();

Log.d("test111 ", ""+p1[0]+","+p1[1]);

m1.postTranslate(100, 300);

m1.postScale(0.6f, 0.3f);

m1.postRotate(45.f);

// 这个过程是将p1{1000f,100f}这个点通过了m1的转换,变成了一个新的点p1,这时候p1已经变成了转换后的点了。

m1.mapPoints(p1);

Log.d("test222 ", ""+m1.toString());

Log.d("test333 ", ""+p1[0]+","+p1[1]);

// 下面是一个逆向的过程

// 将p1经过转换的点,赋值给p2

p2 = p1;

Log.d("test444 ", ""+p2[0]+","+p2[1]);

// 这里将m1进行了逆向,然后存放在m2里

boolean temp = m1.invert(m2);

Log.d("test555 ", ""+m2.toString());

Log.d("test666 ", ""+temp);

// 这里转换过的点可以理解为转换后的点,通过逆向矩阵m2得到最原始的点的位子,并存放在p2里。

m2.mapPoints(p2);

Log.d("test777 ", ""+p2[0]+","+p2[1]);

图6-5显示了运行的结果。

图6-5 矩阵逆向例子的结果


经验分享:

通过上面的例子我们可以看到,你可能在一个时候只需要用到一部分,及矩阵正向的逻辑,或矩阵逆向的逻辑。需要注意的是下面2个方法:

1)m1.mapPoints(p1);//这个过程是将p1{1000f,100f}这个点通过了m1的转换,变成了一个新的点p1,这时候p1已经变成了转换后的float数组了。

2)m1.invert(m2);//这里将m1进行了逆向,然后存放在m2里

时间: 2024-10-05 09:49:55

第六章 一张白纸好作画—Canvas画布(5)的相关文章

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

第六章 一张白纸好作画-Canvas画布 前面的相关章节,我们详细说明过Android UI组件的使用.通过前面章节的学习,开发者已经可以开发出令人满意的UI效果了.但是有的时候,我们需要实现更加漂亮的UI效果,此时可能就无法直接使用UI组件,而是需要自己画出各种UI效果了. 在Android中,Canvas就是一个画布,开发者可以在画布上绘制想要的任何东西.在本章中,我们将介绍Canvas及相关的技术. 6.1 Canvas画布介绍 6.1.1View Canvas-使用普通View的Canv

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

6.2 Canvas常用绘制方法 前面一节我们了解到如果创建一个画布,接下来我们就将要在这个画布上进行绘制.Android SDK的Canvas类中包含了一系列用于绘制的方法,方法分为3种类型,下面简单介绍这些常用的绘制方法. 1)Canvas类的几何图形(Geometry)方面的方法用于绘制点.绘制线.绘制矩形.绘制圆弧等. 其中一些主要的方法如表6-1所示: 方法 返回值 说明 drawARGB(int a, int r, int g, int b) void 将整体填充为某种颜色 draw

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

6.4 Canvas绘制的辅助类 通过前面对Canvas的介绍,我们明白Canvas可以做很多事,绘画图形,变换等,当然在手机世界里我们看到的远远不是简单的图形就可以表现完全的,还有颜色,字体,等各种各样的元素组成,专门的工作交给专门的类来处理.下面我们介绍一些Canvas常用到的一些辅助类. 6.4.1画笔android.graphics.Paint 在Canvas绘制的辅助类中,使用频率最多的是画笔类-Paint.在Canvas的绘制的方法中都带有一个参数,Paint.这个参数就是画笔,Pa

第六章 一张白纸好作画—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

《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章将帮助你解决许多常见的.复杂的建模问题,并解决你可能在现实中遇到的建模问题. 本章以多对多关系开始,这个类型的关系,无论是在现存系统还是新项目的建模中都非常普遍.接下来,我们会了解自引用关系,并探索获取嵌套对象图的各种策略.最后,本章以继承的高级建模和实体条件结束. 6-1  获取多对多关联中的链接表 问题

JavaScript DOM编程艺术-学习笔记(第五章、第六章)

第五章: 1.题外话:首先大声疾呼,"js无罪",有罪的是滥用js的那些人.js的father 布兰登-艾克,当初为了应付工作,10天就赶出了这个js,事后还说人家js是c语言和self语言"约"的产物,(百度百科说的,这些).....一个可怜的孩子-js.然后命运弄"人",js此时已世人皆知.可能是因为js的毁誉参半,它老爸才不想承认它吧.如果js会说话,它可能会给它布兰登-艾克说,"你当初怎么不把*******在墙上".这

再读大道至简第六章

大道之简临近了尾声,作者也开始了“与前文相呼应”,第六章的内容大部分建立在前面五章的基础之上,对相关的名词进行了进一步的阐释,理解,对有关的概念进行了扩充. 一开始说了,语言只是工具,这几乎与第一章的内容相呼应,不讲JAVA/C/C++等等语言的好坏,只是把他们放在工具的层面来说.没有对语言的膜拜也没有对语言的漠视.语言再不同,只是工具不同,适用于不同的环境.就像是犁地不需要铲子,扫地需要扫把一样的.笔者借由各种语言只是工具来引出了,那张幻灯片.看清代码.方法.工程.组织的关系. 在代码.方法.

阅读笔记3——《大道至简》第四、五、六章

“流于形式的沟通,可能是使得你的项目被不断推翻和不断延迟的最直接原因”,这是第四章的最后一句话,是我印象最深刻的一句话. 当我们在与客户交流时,要用客户能懂得方式,并且要保障每一次沟通的有效性,求道于盲是没有错误的,错误的是你睁着眼睛.现在很多公司和客户谈项目时总喜欢去吃饭,吃饭是没有错误的,但最终的结果大多是以酒醉收场.所以就需要最有效的沟通方式来减少各方面的损失,而这个最有效的方式则是通过各方面考究查询得知的.除此之外,我们在做项目时,要记得留下整个项目的历史记录,例如,在需求阶段,与谁联系

MiS603开发板 第十六章 图像之VGA接口测试

作者:MiS603开发团队 日期:20150911 公司:南京米联电子科技有限公司 论坛:www.osrc.cn 网址:www.milinker.com 网店:http://osrc.taobao.com EAT博客:http://blog.chinaaet.com/whilebreak 博客园:http://www.cnblogs.com/milinker/ MiS603开发板 第十六章 图像之VGA接口测试 第十六章图像之VGA接口测试 在本章开始介绍视频图像处理开发平台的硬件结构,主要包括