Android Graphics专题(1)--- Canvas基础
作为Android Graphics专题的开篇。毫无疑问,我们将讨论Android UI技术的核心概念——Canvas。
Canvas是Android UI框架的基础,在Android的控件体系中。全部容器类、控件类在实现上都依赖于Canvas。界面的绘制实质上都是Canvas绘制的。本文将讨论Canvs的由来。并通过实例展示Canvas的基础使用方法。
对于应用开发而言,我们能够不去深究Canvas与Android
控件体系的实现细节,但明确Canvas与控件的关联有助于我们更好的使用Canvas。Android控件体系不是了解的朋友能够參见博文《Android原理揭秘系列之View、ViewGroup》。
先看下Android全部控件的基类——View.java的代码片段:
…
protected void onDraw(Canvas canvas) {
}
….
熟悉Andriod应用开发的人对onDraw方法一定不会陌生。View基类里onDraw方法里是空的。但请注意,方法传入了形參——Canvas对象,也就是说。Canvas对象是UI体系流程中已经创建好的。我们直接拿来用就可以,一般不须要自己构造。Canvas的典型使用场景是,在自己定义控件重载基类的onDraw方法,并在onDraw方法中通过Canvas绘制我们想要的图形、图片等效果。
我们再看看容器类的基类——ViewGroup.java的dispatchDraw方法的代码片段:
protected void dispatchDraw(Canvas canvas) {
…
for (int i = 0; i < count; i++) {
…
more |= drawChild(canvas, child, drawingTime);
}
…
}
dispatchDraw方法是ViewGroup分发绘制子View的核心函数,其通过drawChild方法详细绘制各个子View。这里我们仅仅须要注意Canvas对象的出现位置,相同。Canvas作为形參从dispatchDraw方法传入。并传给drawChild方法用以绘制子view。
通过View和ViewGroup两个核心函数的代码片段分析。我们可以很清晰的明白Canvas在控件体系中的作用。以及我们接下来将讨论的Canvas使用方法的canvas对象来自何处。
Canvas在概念上能够理解为其他编程语言中的画布,在画布中。我们能够绘制各种图形。也能够绘制图片,更深层次的。如上ViewGroup的dispatchDraw方法所描写叙述的。我们能够通过变换Canvas,进而在容器内中自己定义的绘制子控件。
本文仅仅讨论Canvas的基础使用方法,即在自己定义控件重载的onDraw方法中,使用Canvas来绘制主要的图形、图像等基础使用方法。
Android的官方SDK中罗列了Canvas的全部API,可点击具体查看。
这里罗列下在实际应用开发中用得很普遍的几个API:
1)
绘制Bitmap:drawBitmap、drawPicture
2)
绘制颜色:drawColor、drawARGB
3)
绘制基本形状:drawPoint、drawLine、drawCircle、drawArc、drawRect、drawRoundRect
4)
绘制剪切区:drawPath、clipPath、clipRect、clipRegion
5)
变换Canvas:save、restore、translate、scale、rotate、concat(Matrix
matrix)、setMatrix(Matrix
matrix)
6)
绘制顶点数据:drawVertices、drawBitmapMesh
上面的六项基本概况了Canvas的使用得最普遍的API。各API的详细含义和使用方法參见SDK。熟练掌握这些API的功能和使用方法基本能够满足开发须要。
以下通过两个代码演示样例来演示Canvas的基本使用方法。
演示样例1:绘制Bitmap
private static class SampleView extends View {
private Bitmap mBitmap;
private Bitmap mBitmap2;
private Bitmap mBitmap3;
private Bitmap mBitmap4;
public SampleView(Context context) {
super(context);
setFocusable(true);
java.io.InputStream is;
is = context.getResources().openRawResource(R.drawable.beach);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm;
opts.inJustDecodeBounds = true;
bm = BitmapFactory.decodeStream(is, null, opts);
opts.inJustDecodeBounds = false;
opts.inSampleSize = 4;
bm = BitmapFactory.decodeStream(is, null, opts);
mBitmap = bm; //通过配置參数解码生成Bitmap
is = context.getResources().openRawResource(R.drawable.frog);
mBitmap2 = BitmapFactory.decodeStream(is); //通过打开资源ID直接解码图片
int w = mBitmap2.getWidth();
int h = mBitmap2.getHeight();
int[] pixels = new int[w*h];
mBitmap2.getPixels(pixels, 0, w, 0, 0, w, h);
mBitmap3 = Bitmap.createBitmap(pixels, 0, w, w, h,
Bitmap.Config.ARGB_8888);
//通过缓冲区数据构造Bitmap
mBitmap4 = Bitmap.createBitmap(pixels, 0, w, w, h, Bitmap.Config.ARGB_4444);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC);
Paint p = new Paint();
p.setAntiAlias(true); //设置防锯齿
canvas.drawBitmap(mBitmap, 10, 10, null);
canvas.drawBitmap(mBitmap2, 10, 170, null);
canvas.drawBitmap(mBitmap3, 110, 170, null);
canvas.drawBitmap(mBitmap4, 210, 170, null); //通过drawBitmap绘制图
}
}
演示样例1通过继承基类View实现了一个绘制Bitmap的自己定义View SampleView,SampleView在构造函数中通过几种不同的方式分别构造了四个不同的Bitmap,在onDraw方法中,通过onDraw方法传入的canvas绘制Bitmap。
这样实现的控件在界面上将依据不同的坐标位置绘制出四幅图片的效果。注意,因为Android
View的onDraw方法在界面显示、隐藏、遮挡等非常多场合都会被系统频繁调用,因此,像构造Bitmap这种耗费较大内存资源的工资不应该放在onDraw方法中去运行。
演示样例2:绘制顶点数据实现变形效果
private static class SampleView extends View {
private final Paint mPaint = new Paint();
private final float[] mVerts = new float[10];
private final float[] mTexs = new float[10];
private final short[] mIndices = { 0, 1, 2, 3, 4, 1 };
private final Matrix mMatrix = new Matrix();
private final Matrix mInverse = new Matrix();
private static void setXY(float[] array, int index, float x, float y) {
array[index*2 + 0] = x;
array[index*2 + 1] = y;
}
public SampleView(Context context) {
super(context);
setFocusable(true);
Bitmap bm = BitmapFactory.decodeResource(getResources(),
R.drawable.beach);
Shader s = new BitmapShader(bm, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mPaint.setShader(s);//通过BitmapShader设置Paint的Shader
float w = bm.getWidth();
float h = bm.getHeight();
// construct our mesh
setXY(mTexs, 0, w/2, h/2);
setXY(mTexs, 1, 0, 0);
setXY(mTexs, 2, w, 0);
setXY(mTexs, 3, w, h);
setXY(mTexs, 4, 0, h); //初始化图片纹理映射坐标
setXY(mVerts, 0, w/2, h/2);
setXY(mVerts, 1, 0, 0);
setXY(mVerts, 2, w, 0);
setXY(mVerts, 3, w, h);
setXY(mVerts, 4, 0, h);//初始化顶点数据数组
mMatrix.setScale(0.8f, 0.8f);
mMatrix.preTranslate(20, 20);
mMatrix.invert(mInverse); //初始化变形矩阵
}
@Override protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC); //绘制背景色
canvas.save(); //变形canvas前先保存canvas现场
canvas.concat(mMatrix); //设置变换矩阵
canvas.drawVertices(Canvas.VertexMode.TRIANGLE_FAN, 10, mVerts, 0,
mTexs, 0, null, 0, null, 0, 0, mPaint);
//绘制当前顶点坐标和纹理坐标决定的图片Paint,得到图片变形效果。
canvas.translate(0, 240);//向下平移canvas
canvas.drawVertices(Canvas.VertexMode.TRIANGLE_FAN, 10, mVerts, 0,
mTexs, 0, null, 0, mIndices, 0, 6, mPaint);
//绘制当前顶点坐标和纹理坐标和索引数组决定的图片Paint,得到另外的图片变形效果。
canvas.restore();//变换完毕后恢复canvas现场
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float[] pt = { event.getX(), event.getY() };
mInverse.mapPoints(pt); // 依据当前的触摸位置变换Marix
setXY(mVerts, 0, pt[0], pt[1]); //据触摸的位置变换顶点坐标
invalidate();//刷新界面。触发onDraw方法被再次调用
return true;
}
}
演示样例2是Canvas的一个比較综合性的使用方法演示样例,用到了canvas的多个API,理解了该演示样例。对Canvas的使用方法基本就达到了比較熟练的程度。该演示样例的一些新的概念如Paint、Shader、Matrix等概念兴许专题会作有专门的介绍,敬请关注。
演示样例2有例如以下一些知识点:
1) 用户的触摸事件在onTouchEvent中传入,通过传入event參数能够获取当前触摸膜的坐标点,并依据这个坐标位置參数来改变算法的相关參数,进而达到依据不同的坐标位置来达到变形的目的。
2)
调用View的invaidate方法能够触发View的重绘流程。重而触发onDraw方法的调用。
3)能够通过canvas的drawColor方法来绘制View的背景色。
4) 因为在onDraw方法中传入的Canvas參数是一个引用。该canvas对象在其它地方还会使用,因此。假设绘制中会改变canvas的几何參数,须要在变换前后採用canvas.save()、canvas.restore()方法对来备份和恢复canvas现场。
注意,这两个方法必须成对出现。否则会导致严重的波及问题。
5)
变换canvas的几何參数能够通过concat连接Maxrix矩阵或者translate平移、scalse缩放、rotate旋转等方法来实现。
6)能够通过drawVertices方法绘制具有变形图片的效果,详细变形的样式取决于顶点坐标、纹理坐标、索引数组和Paint设置的BitmapShader。
灵活使用该API能够以2D的API实现近似3D的效果。与drawVertices类似的API还有drawBitmapMesh,能够实现基于网格顶点的复杂3D效果。
演示样例2的执行效果參见下图:
本文是Android Canvas的基础篇,主要讨论Canvas的一些基本概念和经常使用API,兴许文章中将继续涉及Canvas的方方面面。
Android
Graphics专题的下一篇文章将聚焦Graphics中用得很普通的概念——Paint。敬请期待。
我的手机专卖店,欢迎各位看官捧场:http://vpclub.octech.com.cn/ztewd/9495.html
Android Graphics专题(1)--- Canvas基础的更多相关文章
- android.graphics(1) - Paint, Canvas, drawLine, drawPoint, drawRect, drawRoundRect, drawCircle, drawOval, drawArc
一.Paint与Canvas 像我们平时画图一样,需要两个工具,纸和笔.Paint就是相当于笔,而Canvas就是纸,这里叫画布. 所以,凡有跟要要画的东西的设置相关的,比如大小,粗细,画笔颜色,透明 ...
- 【转】android Graphics(四):canvas变换与操作
android Graphics(四):canvas变换与操作 分类: 5.andriod开发2014-09-05 15:05 5877人阅读 评论(18) 收藏 举报 目录(?)[+] 前言 ...
- android Graphics(四):canvas变换与操作
前言:前几篇讲解了有关canvas绘图的一些操作,今天更深入一些,讲讲对画布的操作,这篇文章不像前几篇那么容易理解,如果以前没有接触过画布的童鞋可能比较难以理解,为什么会这样.我尽量多画图,让大家更清 ...
- Canvas: trying to use a recycled bitmap android.graphics.Bitmap@XXX
近期在做和图片相关显示的出现了一个问题,整理一下思路.分享出来给大家參考一下: Exception Type:java.lang.RuntimeException java.lang.RuntimeE ...
- android SurfaceView绘制 重新学习--基础绘制
自从大二写了个android游戏去参加比赛,之后就一直写应用,一直没用过SurfaceView了,现在进入了游戏公司,准备从基础开始重新快速的学一下这个,然后再去研究openGL和游戏引擎. 直接上代 ...
- android Graphics(三):区域(Range)
前言:最近几天对画图的研究有些缓慢,项目开始写代码了,只能在晚上空闲的时候捯饬一下自己的东西,今天给大家讲讲区域的相关知识,已经想好后面两篇的内容了,这几天有时间赶紧写出来给大家.有关界面开发的东东内 ...
- android Graphics(一):概述及基本几何图形绘制
前言:我最近想抽空研究研究android的各种特效,android的特效真是其它平台无法比拟的,而且一个漂亮的UI交互,会给APP增色不少,而学习特效之前,有关graphics绘图的基础知识是必不可少 ...
- 【Android开发日记】之基础篇(二)——Android的动画效果
什么是动画,动画的本质是通过连续不断地显示若干图像来产生“动”起来的效果.比如说一个移动的动画,就是在一定的时间段内,以恰当的速率(起码要12帧/秒以上,才会让人产生动起来的错觉)每隔若干 ...
- android.graphics.Matrix
Matrix类包含了一个3x3的矩阵用来改变坐标,它没有一个构造器来初始化它里边的内容,所以创建实例后需要调用reset()方法生成一个标准matrix,或者调用set..一类的函数,比如setTra ...
随机推荐
- p类型最大可定义范围
t7(16) TYPE p DECIMALS 14,
- 虚拟机安装中文Fedora14和C/C++IDE开发环境
虚拟机安装中文Fedora14和C/C++IDE开发环境 2010-12-05 00:15:58 标签:中文Fedora14 IDE 开发环境 C/C++ 原创作品,允许转载,转载时请务必以超链接形式 ...
- [概念] js的函数节流和throttle和debounce详解
js的函数节流和throttle和debounce详解:同样是实现了一个功能,可能有的效率高,有的效率低,这种现象在高耗能的执行过程中区分就比较明显.本章节一个比较常用的提高性能的方式,通常叫做&qu ...
- Swift - 类型嵌套(以扑克牌结构体为例)
类型嵌套,简单来说实在一个类型中包含另外一个类型.我们拿一副扑克来说明. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 //类 ...
- 关于Delphi XE2的FMX的一点点研究之消息篇
Delphi XE2出来了一阵子了,里面比较抢眼的东西,除了VCLStyle这个换肤的东西之外,另外最让人眼亮的应该是FMX这个东西了.万一的博客上都连载了一票的关于FMX的使用心得了.我还是没咋去关 ...
- 用Python制作游戏外挂(上)
源地址:http://eyehere.net/2012/python-game-bot-autopy-1/ 悲剧成我这样的人,我知道肯定不止我一个,所以我一点都不悲伤:-( 所以我打开了4399小游戏 ...
- Spring4 MVC 多文件上传(图片并展示)
开始需要在pom.xml加入几个jar,分别是 <dependency> <groupId>commons-fileupload</groupId> <art ...
- Codeforces Round #235 (Div. 2) D. Roman and Numbers (数位dp、状态压缩)
D. Roman and Numbers time limit per test 4 seconds memory limit per test 512 megabytes input standar ...
- ZOJ 3529 A Game Between Alice and Bob(博弈论-sg函数)
ZOJ 3529 - A Game Between Alice and Bob Time Limit:5000MS Memory Limit:262144KB 64bit IO For ...
- 不要打开文件,阅读Rvt信息档案
叶老师,想问一下是否能基于revit API 2014,直接在开发时传递给程序要处理的文件名称和路径.而不用再在revit软件中打开为当前活动视图,就直接获得文件里信息.这样可行不? 答: 能够.你能 ...