作为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、drawLinedrawCircledrawArc、drawRect、drawRoundRect

4) 
绘制剪切区:drawPath、clipPathclipRectclipRegion

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

本文为原创文章,转载请注明出处http://blog.csdn.net/droidpioneer

Android Graphics专题(1)--- Canvas基础的更多相关文章

  1. android.graphics(1) - Paint, Canvas, drawLine, drawPoint, drawRect, drawRoundRect, drawCircle, drawOval, drawArc

    一.Paint与Canvas 像我们平时画图一样,需要两个工具,纸和笔.Paint就是相当于笔,而Canvas就是纸,这里叫画布. 所以,凡有跟要要画的东西的设置相关的,比如大小,粗细,画笔颜色,透明 ...

  2. 【转】android Graphics(四):canvas变换与操作

    android Graphics(四):canvas变换与操作 分类: 5.andriod开发2014-09-05 15:05 5877人阅读 评论(18) 收藏 举报   目录(?)[+]   前言 ...

  3. android Graphics(四):canvas变换与操作

    前言:前几篇讲解了有关canvas绘图的一些操作,今天更深入一些,讲讲对画布的操作,这篇文章不像前几篇那么容易理解,如果以前没有接触过画布的童鞋可能比较难以理解,为什么会这样.我尽量多画图,让大家更清 ...

  4. Canvas: trying to use a recycled bitmap android.graphics.Bitmap@XXX

    近期在做和图片相关显示的出现了一个问题,整理一下思路.分享出来给大家參考一下: Exception Type:java.lang.RuntimeException java.lang.RuntimeE ...

  5. android SurfaceView绘制 重新学习--基础绘制

    自从大二写了个android游戏去参加比赛,之后就一直写应用,一直没用过SurfaceView了,现在进入了游戏公司,准备从基础开始重新快速的学一下这个,然后再去研究openGL和游戏引擎. 直接上代 ...

  6. android Graphics(三):区域(Range)

    前言:最近几天对画图的研究有些缓慢,项目开始写代码了,只能在晚上空闲的时候捯饬一下自己的东西,今天给大家讲讲区域的相关知识,已经想好后面两篇的内容了,这几天有时间赶紧写出来给大家.有关界面开发的东东内 ...

  7. android Graphics(一):概述及基本几何图形绘制

    前言:我最近想抽空研究研究android的各种特效,android的特效真是其它平台无法比拟的,而且一个漂亮的UI交互,会给APP增色不少,而学习特效之前,有关graphics绘图的基础知识是必不可少 ...

  8. 【Android开发日记】之基础篇(二)——Android的动画效果

          什么是动画,动画的本质是通过连续不断地显示若干图像来产生“动”起来的效果.比如说一个移动的动画,就是在一定的时间段内,以恰当的速率(起码要12帧/秒以上,才会让人产生动起来的错觉)每隔若干 ...

  9. android.graphics.Matrix

    Matrix类包含了一个3x3的矩阵用来改变坐标,它没有一个构造器来初始化它里边的内容,所以创建实例后需要调用reset()方法生成一个标准matrix,或者调用set..一类的函数,比如setTra ...

随机推荐

  1. 不容错过的UI设计素材大合集

    免费PSD素材 TETHR by InVision 这是出自InVision的8款PSD文件,其中包含了100个模板和超过500个UI控件.来自InVision和UI8的设计师一同协作完成了这套UI ...

  2. Logistic Regression(逻辑回归)(一)基本原理

    (整理自AndrewNG的课件,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 虽然叫做“回归”,但是这个算法是用来解决分类问题的.回归与分类的区 ...

  3. Http请求工具实例编写(超长,比较清楚)

    HTTP协议工作方式首先客户端发送一个请求(request)给服务器,服务器在接收到这个请求后将生成一个响应(response)返回给客户端.在这个通信的过程中HTTP协议在以下4个方面做了规定:1. ...

  4. Windows 8 动手实验系列教程 实验5:进程生命周期管理

    动手实验 实验5:进程生命周期管理 2012年9月 简介 进程生命周期管理对构建Windows应用商店应用的开发者来说是需要理解的最重要的概念之一.不同于传统的Windows应用(它们即使在后台仍然继 ...

  5. BSGS_Baby steps giant steps算法

    BSGS这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 在具体的题目中,C一般是所有可能事件的总数. 解: 设m = ceil(sqrt(C))(ce ...

  6. Fedora 问题总结第二季

    该系列主要是记录自己使用fedora发现的问题. 1Linux Error: curses.h: No such file or directory Problem Solution sudo yum ...

  7. 使用commons-daemon启动、关闭java程序

    系统环境: CentOS 7 X64 JDK1.8 一: 安装jsvc 下载 commons-daemon的源代码包 http://apache.fayea.com//commons/daemon/s ...

  8. 将n进制的数组压缩成字符串(0-9 a-z)同一时候解压

    比如一个3进制的数组: [1 1 2 2 2 0 0] 用一个字符串表示... 此类题目要明白两点: 1. 打表:用数组下标索引字符.同一时候注意假设从字符相应回数字: int index = (st ...

  9. VC/MFC 在ListCtl 控件中随鼠标移动提示单元格信息

    BEGIN_MESSAGE_MAP(CTipListCtrl, CListCtrl) //{{AFX_MSG_MAP(CTipListCtrl) ON_WM_MOUSEMOVE() ON_WM_DES ...

  10. hdu 1028 母函数 一个数有几种相加方式

    ///hdu 1028 母函数 一个数有几种相加方式 #include<stdio.h> #include<string.h> #include<iostream> ...