Android Graphics专题(1)--- Canvas基础

摘要:
作为Android图形的开端。毫无疑问,我们将讨论Android UI技术的核心概念——画布。通过实例说明了Canvas的基本使用方法。对于应用程序开发,我们无法深入了解Canvas和Android控制系统的实现细节,但明确Canvas和控件之间的关系将有助于我们更好地使用Canvas。让我们先看看View.java的代码片段,它是所有Android控件的基类:。。。本文仅讨论Canvas的基本用法,即在定义控件重载的onDraw方法中,Canvas用于绘制主要图形、图像和其他基本使用方法。官方Android SDK列出了所有Canvas API,可以通过单击查看。

作为Android Graphics专题的开篇。毫无疑问,我们将讨论Android UI技术的核心概念——Canvas

CanvasAndroid UI框架的基础,在Android的控件体系中。全部容器类、控件类在实现上都依赖于Canvas。界面的绘制实质上都是Canvas绘制的。本文将讨论Canvs的由来。并通过实例展示Canvas的基础使用方法。

对于应用开发而言,我们能够不去深究CanvasAndroid 控件体系的实现细节,但明确Canvas与控件的关联有助于我们更好的使用CanvasAndroid控件体系不是了解的朋友能够參见博文《Android原理揭秘系列之ViewViewGroup》。

先看下Android全部控件的基类——View.java的代码片段:

…
protected void onDraw(Canvas canvas) {
 }
….

熟悉Andriod应用开发的人对onDraw方法一定不会陌生。View基类里onDraw方法里是空的。但请注意,方法传入了形參——Canvas对象,也就是说。Canvas对象是UI体系流程中已经创建好的。我们直接拿来用就可以,一般不须要自己构造。Canvas的典型使用场景是,在自己定义控件重载基类的onDraw方法,并在onDraw方法中通过Canvas绘制我们想要的图形、图片等效果。

我们再看看容器类的基类——ViewGroup.javadispatchDraw方法的代码片段:

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

通过ViewViewGroup两个核心函数的代码片段分析。我们可以很清晰的明白Canvas在控件体系中的作用。以及我们接下来将讨论的Canvas使用方法的canvas对象来自何处。

Canvas在概念上能够理解为其他编程语言中的画布,在画布中。我们能够绘制各种图形。也能够绘制图片,更深层次的。如上ViewGroupdispatchDraw方法所描写叙述的。我们能够通过变换Canvas,进而在容器内中自己定义的绘制子控件。

本文仅仅讨论Canvas的基础使用方法,即在自己定义控件重载的onDraw方法中,使用Canvas来绘制主要的图形、图像等基础使用方法。

Android的官方SDK中罗列了Canvas的全部API可点击具体查看

这里罗列下在实际应用开发中用得很普遍的几个API:

1)  绘制BitmapdrawBitmapdrawPicture

2)  绘制颜色:drawColordrawARGB

3)  绘制基本形状:drawPointdrawLinedrawCircledrawArcdrawRectdrawRoundRect

4)  绘制剪切区:drawPathclipPathclipRectclipRegion

5)  变换Canvassaverestoretranslatescalerotateconcat(Matrix matrix)setMatrix(Matrix matrix)

6)  绘制顶点数据:drawVerticesdrawBitmapMesh 

上面的六项基本概况了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 SampleViewSampleView在构造函数中通过几种不同的方式分别构造了四个不同的Bitmap,在onDraw方法中,通过onDraw方法传入的canvas绘制Bitmap

这样实现的控件在界面上将依据不同的坐标位置绘制出四幅图片的效果。注意,因为Android ViewonDraw方法在界面显示、隐藏、遮挡等非常多场合都会被系统频繁调用,因此,像构造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; } }

 演示样例2Canvas的一个比較综合性的使用方法演示样例,用到了canvas的多个API,理解了该演示样例。对Canvas的使用方法基本就达到了比較熟练的程度。该演示样例的一些新的概念如PaintShaderMatrix等概念兴许专题会作有专门的介绍,敬请关注。

演示样例2有例如以下一些知识点:

1) 用户的触摸事件在onTouchEvent中传入,通过传入event參数能够获取当前触摸膜的坐标点,并依据这个坐标位置參数来改变算法的相关參数,进而达到依据不同的坐标位置来达到变形的目的。

2)  调用Viewinvaidate方法能够触发View的重绘流程。重而触发onDraw方法的调用。

3)能够通过canvasdrawColor方法来绘制View的背景色。

4) 因为在onDraw方法中传入的Canvas參数是一个引用。该canvas对象在其它地方还会使用,因此。假设绘制中会改变canvas的几何參数,须要在变换前后採用canvas.save()canvas.restore()方法对来备份和恢复canvas现场。

注意,这两个方法必须成对出现。否则会导致严重的波及问题。

5)  变换canvas的几何參数能够通过concat连接Maxrix矩阵或者translate平移、scalse缩放、rotate旋转等方法来实现。

6)能够通过drawVertices方法绘制具有变形图片的效果,详细变形的样式取决于顶点坐标、纹理坐标、索引数组和Paint设置的BitmapShader

灵活使用该API能够以2DAPI实现近似3D的效果。与drawVertices类似的API还有drawBitmapMesh,能够实现基于网格顶点的复杂3D效果。

演示样例2的执行效果參见下图:

Android Graphics专题(1)--- Canvas基础第1张

本文是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基础》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【 CodeForcesVSCode设置中文语言显示下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

canvas 钟表

上周开始利用闲暇时间看html5 canvas技术。觉得非常好玩。就利用 canvas 做了一个简陋的钟表。源码非常简单,但是在制作的过程中,进入的误区却不少,浪费了很多时间。先上源码,然后在说说我走的岔路。 源码是基于 require.js 去写的,可以去 官网 了解 require.js 的详细资料。 1 define(function(){ 2...

html 通过input video canvas 打开摄像头 定制相机

在机缘巧合之下,了解到用HTML5和javascript调用摄像头来实现拍照功能,今天就把大致原理写下来。页面布局很简单,就是一个input标签,两个HTML5元素video、canvas和一个button按钮。video元素带有开启视频功能的函数,canvas元素带有捕捉图像功能的函数。 源代码如下: <!doctype html><h...

Canvas:绘制路径

Canvas:绘制路径 绘制路径   图形的基本元素是路径。路径是[通过不同颜色和宽度的线段或曲线相连形成的不同形状的]点的集合。一个路径,甚至一个子路径,都是闭合的。   使用路径绘制图形需要一些额外的步骤。 首先,你需要创建路径起始点。 然后你使用画图命令去绘制路径。 之后把路径进行封闭。 一旦路径生成,你就能通过描边或填充路径区域来渲染图形。 函...

canvas 实现小人的行走和上下左右的变换

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>小人行走动画</title></head><body> <canvas width="600"&...

chromium截图实现

声明:本blog是我自己写的,假设要转载,请注明:come from blog of niba! chromium终于显示是在ContentView上。但通过硬件加速。渲染合成的网页之前是在surfaceview上的。 所以。实现chromium的截图能够通过SufraceView的截图去实现。   自己创建一个SurfaceView的子类,例如以下:...

vue截图界面保存本地

使用html2canvas把界面生成图片 下载 html2canvas 依赖: npm install html2canvas -S 需要使用 html2canvas 页面引入该依赖: import html2canvas from 'html2canvas' html代码: <template> <div>...