| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> Android canvas -> 正文阅读 |
|
[游戏开发]Android canvas |
1.Canvas Canvas是一个画布,可以在这个画布上进行各种绘图操作。 ①继承一个View,并重写onDraw()方法。View的Canvas对象会被当做参数传递过来,在这个Canvas上进行的操作会直接反映在View中。 ②调用SurfaceHolder.lockCanvas()返回一个Canvas对象。 ③通过构造方法自己创建一个Canvas对象。 Bitmap bitmap = Bitmap.createBitmap(100f, 100f, Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); ? Canvas的坐标系: 画布以左上角为原点(0,0),向右为X轴的正方向,向下为Y轴的正方向: ? 2.Canvas的常用方法 ①对整个Canvas坐标系的操作 //平移画布。dx,dy为x,y轴上的移动距离 public void translate(float dx, float dy) //以坐标点(0,0)旋转画布。degress为旋转角度 public void rotate(float degrees) //以坐标点(px,py)旋转画布。degress为旋转角度 public final void rotate(float degrees, float px, float py) //以坐标点(0,0)缩放画布。sx,sy为x,y轴上的缩放倍数 public void scale(float sx, float sy) //以坐标点(px,py)缩放画布。sx,sy为x,y轴上的缩放倍数 public final void scale(float sx, float sy, float px, float py) //倾斜画布。sx,sy为x,y轴上的倾斜角度的tan值 public void skew(float sx, float sy) ? 3.Canvas的回退栈 当我们使用canvas的辅助函数,对canvas进行操作时,这些操作都是不可逆的。比如,在绘制某个内容之前,使用clipRect(0,0,100,100),那么之后的绘制就只能在[0,0,100,100]这个矩形内,除非在通过手动调用api,让canvas回到之前的某个状态。 Canvas在进行上面的平移、缩放、旋转、倾斜后,画布的状态也就随之改变。这可能对后面的绘图操作产生很多麻烦。比如我们为了某些效果不得不对画布进行一些操作,但操作完了,画布状态也就改变了。 为了避免发生这种情况,就可以在特定的位置进行保存和恢复,在进行变换前,使用save保存canvas当前的状态,然后进行变换,接着绘制我们要绘制的内容,最后再通过restore恢复之前保存的状态。 如果在一次绘制中,多次调用save方法,那么会将每次save时canvas的状态压入类似一个栈中,每一个状态都对应一个数字,代表其是栈中的第几个,可以通过方法restoreToCount(count),将canvas回退到指定的那个。也可以调用restore,一个一个的回退canvas的状态。 public int save()? ?每次调用该方法,都会把当前画布的状态进行保存,并存放在一个栈结构中 public void restore()? ?每次调用该方法,都会把栈中最顶层的画布状态取出来,并按照这个画布状态恢复当前画布。如果当前栈中没有保存的画布状态,则会抛出异常。 canvas还提供了一个restoreToCount(int saveCount) 来恢复画布状态。每次调用save()方法保存画布状态时都会返回一个int型的值。我们可以把该值直接传入restoreToCount()方法中直接恢复画布状态。状态恢复后,会将该状态和该状态顶部的其他画布状态一同出栈。 public void restoreToCount(int saveCount)? ?恢复指定的画布状态 需要注意的是,不管是调用restore还是restoreToCount,都需要在save的数量范围内,否者系统就会抛出异常。 ? 4.Canvas的绘图操作 Canvas 拥有大量的drawXXX()方法,这些方法用于在画布上绘制各种图形,下面为一些常用的绘图方法: //绘制颜色 public void drawColor(@ColorInt int color) public void drawRGB(int r, int g, int b) public void drawARGB(int a, int r, int g, int b) //绘制圆 public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) //绘制点 public void drawPoint(float x, float y, @NonNull Paint paint) //绘制多个点 public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) //绘制一条直线 public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) //绘制多条直线 public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) //绘制一个矩形 public void drawRect(@NonNull RectF rect, @NonNull Paint paint) public void drawRect(@NonNull Rect r, @NonNull Paint paint) public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) //绘制一个圆角矩形 public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint) //绘制一个椭圆 public void drawOval(@NonNull RectF oval, @NonNull Paint paint) public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) //绘制一个弧形 public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) //绘制文本 public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) //沿Path路径绘制文本 public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint) //绘制位图 public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint) ? 当我们使用canvas.drawXXX时,系统会在一个新的透明区域,绘制我们要绘制的内容,然后迅速与屏幕当前显示内容进行重叠,这个重叠的过程也会受xfermode或blendmode的影响。 如下示例,就演示了这个情况: 不设置xfermode: override fun onDraw(canvas: Canvas) { ? ? //先将背景涂红 ? ? canvas.drawColor(Color.RED) ? ? //在中心画一个绿色的圆 ? ? paint.color = Color.GREEN ? ? canvas.drawCircle( width/2f, height/2f, radios/2f, paint) } 得到的结果是这样的: ?设置xfermode为DST: override fun onDraw(canvas: Canvas) { ? ? //先将背景涂红 ? ? canvas.drawColor(Color.RED) ? ? //在中心画一个绿色的圆 ? ? paint.xfermode = PorterDuffXfermode( PorterDuff.Mode.DST) ? ? paint.color = Color.GREEN ? ? canvas.drawCircle( width/2f, height/2f, radios/2f, paint) ? ? paint.xfermode = null } 得到的结果是这样的: ?如果在绘制过程中只是给paint设置xfermode,而没有进行操作,如保存Canvas状态信息等,那么: ①如果设置的mode需要削掉DST(即已经在屏幕上显示的)部分或全部内容,那么这个mode不会生效 ②如果设置的mode为SRC_OUT、DST_OUT或XOR时,那么SRC区域显示为黑色,再覆盖在已显示的内容上 ? 5.使用layer综合绘制操作 既然只是直接使用paint.setXfermode设置的效果,会跟预期的不一致,那么应该怎么样才能获得预期的效果呢? canvas提供了saveLayer方法,抽取一个透明区域,执行绘制方法,随后再一并将绘制的内容,覆盖在已显示内容上。 调用saveLayer()可以为canvas创建一个新的图层,在新的图层上的绘制并不会直接绘制在屏幕上,而是在restore()后绘制在上一个图层或者绘制在屏幕上(如果没有上一个图层)。创建一个新图层的好处之一是我们在处理xformode的时候,原图层上的图片和背景都会影响dst和src的合成。这时使用一个新图层是一个很好的选择。 //创建一个指定大小的图层 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) Canvas还提供了另外两个方法用于创建指定透明度的图层,在该图层上绘制的图形都会带有指定的透明度: //创建一个指定大小和透明度的图层。参数alpha为透明度,取值为0到255 public int saveLayerAlpha(@Nullable RectF bounds, int alpha) public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) 使用和不使用saveLayer的大致工作流程: ①不使用layer ?②使用layer 在调用saveLayer时,可以传入一个saveFlags参数,它有如下几个参数可以设置: MATRIX_SAVE_FLAG? 只保存图层的matrix矩阵 CLIP_SAVE_FLAG? 只保存大小信息 HAS_ALPHA_LAYER_SAVE_FLAG? ? 表明该图层有透明度,和下面的标识冲突,都设置时以下面的标志为准 FULL_COLOR_LAYER_SAVE_FLAG? ?完全保留该图层颜色(和上一图层合并时,清空上一图层的重叠区域,保留该图层的颜色) CLIP_TO_LAYER_SAVE_FLAG? ?创建图层时,会把canvas(所有图层)裁剪到参数指定的范围,如果省略这个flag将导致图层开销巨大(实际上图层没有裁剪,与原图层一样大) ALL_SAVE_FLAG? 保存所有信息 ? ? ? ? 需要注意,如果绘制过程需要对canvas进行多次的几何变换,那么需要倒叙来写几何变换过程。比如需要先平移再旋转,那么在写代码的时候,就需要先旋转再平移。 这里主要是因为屏幕的坐标系和canvas坐标系是两个坐标系,需要进行一定的的空间想象。 当然,也可以初始化一个Matrix,合理的使用preXXX和postXXX,对该Matrix进行几何变换操作,然后将其应用到canvas上。 ? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/16 17:36:05- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |