android canvas与图层的关系

在自定义view中可以通过canvas在屏幕上绘制一些文字,图片,图形之类的效果,canvas这个类给我们提供了很多绘制的方法,比如绘制一段文字在屏幕上:

package com.example.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by admin on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint = null;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setTextSize(35);//设置文字大小
        canvas.drawText("canvas绘制文字",100,100,mPaint);
    }
}

这是在父view的100,100坐标哪里绘制文字的,canvas绘制的方法一般都是前缀draw....比入drawBitmap()绘制图片,Canvas类如下方法:

canvas方法多用几篇就知道了,今天主要是讲canvas与图层的关系,先讲下canvas几个方法

1:translate(floatdx,
floatdy)

package com.example.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by Adminis on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Rect rect = new Rect(0,0,400,400);
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        canvas.drawRect(rect,mPaint);
    }
}

效果如下:

现在通过canvas的translate(100,100)向右平移100px,向下平移100px,效果:

从效果来看就知道translate(dx,dy)这二个参数的意思

dx:是向右移动dx距离

dy:是向下移动dy距离

canvas还有其他类似view的动画方法

scale(dx,dy)缩放

rotate(dx,dy)旋转

这是一些canvas实现对画布的操作,但是有没有想过这个矩形是怎么画上去的,也许会说这不是废话么,通过canvas画上去的,所以就得出结论就是画布就是屏幕显示区域,现在把上面绘制的矩形改为空心的

package com.example.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by Adminis on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Rect rect = new Rect(0,0,400,400);
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawRect(rect, mPaint);
        canvas.translate(100,100);
        mPaint.setColor(Color.GREEN);
        canvas.drawRect(rect, mPaint);
    }
}

图:

发现平移后的矩形和平移前的矩形没有重合,这是为什么呢?这是因为屏幕显示和canvas不是一个等同的概念,屏幕相当于一个显示我们所看到效果的一个容器,你可以随便往屏幕上显示任何可在坐标点范围内可见的,而canvas可以看作是一个透明的图层,我们每次调用canvas的draw...方法都会产生一个透明的层,既然知道了canvas每次draw都会产生一个透明的图层,这样也就好解释上面的问题,在没有平移前,它的坐标点为(0,0) 平移了(100,100)相当于(100,100)是第二个图层的原点,这样二个图层就有重叠的部分,而canvas对象是系统通过onDraw()方法提供给我们的显示到屏幕上,关于屏幕于canvas图层我在别的博客找到了一个很好的图演示图层合成到屏幕上

而图层是无限大的,而屏幕大小是有限的,比如在使用canvas把一段位子绘制到图层上的坐标是负数,而在屏幕上显示不出来就是就是因为屏幕是从(0,0)到(屏幕的宽度,屏幕的高度)这个范围是可见的,超过这二个点的范围是不可见的,既然在图层上画出来也显示看不见的,从上面的分析中可得出2个结论

1:每次调用canvas对象的draw...方法都会产生一个透明的图层

2:canvas与屏幕合成过程中,如果超出屏幕范围是不可见的,

canvas还有2个非常重要的方法 一般使用了canvas的什么平移,缩放等操作必用到的2个方法就是save()和restore()

你可以在屏幕上绘制多个图层,我们知道activity有activity任务栈,你也可以想象的把图层集合想象成一个栈,栈是一个先进后出的数据结构,你可以把图层看作是一个activity任务栈,一层一层的往屏幕上叠起来,现在写个例子:

package com.example.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by Adminis on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制一个图层背景  没有在图层上画什么东西 一个空的图层
        canvas.drawColor(Color.parseColor("#e5e5e5"));
        //保存当前画布大小即整屏 (这是保存上一个画布的操作)
        canvas.save();
        //绘制一个矩形
        canvas.clipRect(new Rect(100, 100, 800, 800));
        canvas.drawColor(Color.GREEN);
        //恢复整屏画布 也就是回复到(0,0)坐标点
        canvas.restore();
        canvas.drawColor(Color.);
    }
}

这三个图层可以一个个画出来看出它的合成到屏幕的过程,结果是这样的,

第二个图层:第二个图层的宽度800-100,高度为800-100就是图中显示的区域大小

第三层:

最终是显示整屏的红色,因为最后一层是(0,0)开始会把前2层图层覆盖了,如果canvas不调用restore()回复的方法 效果是这样的:

你会发现它刚好在第二个图层的上面,我们可以在第三个图层画一个矩形,但是宽和高比第二个图层的矩形小点,这样就可以看出来它在第二个层上面,

package com.example.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by Adminis on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制一个图层背景  没有在图层上画什么东西 一个空的图层
        canvas.drawColor(Color.parseColor("#e5e5e5"));
        //保存当前画布大小即整屏 (这是保存上一个画布的操作)
        canvas.save();
        //绘制一个矩形
        canvas.clipRect(new Rect(100, 100, 800, 800));
        canvas.drawColor(Color.GREEN);
//        //恢复整屏画布 也就是回复到(0,0)坐标点
//        canvas.restore();
        canvas.clipRect(new Rect(100, 100,700, 700));
        canvas.drawColor(Color.RED);
    }
}

效果:

从效果上可以得出一个结论,如果canvas没有调用restore()方法的话,canvas画图层是从它上一个图层栈中以上一个图层原点为原点开始绘制并合并到屏幕上,现在写一个例子多次调用save()和restore()方法会有什么奇怪的效果出来:

package com.example.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
/**
 * Created by Adminis on 2016/5/9.
 */
public class CustomView extends View {
    private Paint mPaint;
    public CustomView(Context context) {
        super(context);
    }
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
    }
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.parseColor("#e5e5e5"));
        //保存的画布大小为全屏幕大小
        canvas.save();
        //这个矩形会在上一个画布上进行draw 也就是(0,0)位置
        canvas.clipRect(new Rect(100, 100, 600, 600));
        //这个画布在前一个矩形大小为500,500的位置
        canvas.drawColor(Color.GREEN);
        //保存画布大小为Rect(100, 100, 600, 600)
        canvas.save();
        //这个会在上一个矩形为500,500的位置上
        canvas.clipRect(new Rect(200, 200, 700, 700));
        canvas.drawColor(Color.BLUE);
        //保存画布大小为Rect(200, 200, 700, 700)
        canvas.save();
        //这个会在原点为(200,200)大小为500的我、canvas上
        canvas.clipRect(new Rect(300, 300, 600, 600));
        canvas.drawColor(Color.BLACK);
        //保存画布大小为Rect(300, 300, 600, 600)
        canvas.save();
        //这个会在原点为(300,300)为原点大小为300的位置上进行canvas
        canvas.clipRect(new Rect(400, 400, 500, 500));
        canvas.drawColor(Color.YELLOW);
    }
}

这个注释写的很仔细了,最终的效果图:

这是调用了四次save()方法但是没调用restore()方法,可以模拟activity栈画一个类似activity任务栈的图:

现在可以先调用一次restore()方法看效果:为了看出效果我把最后一层的大小和上一层大小一样

你会发现把上一层黑色的给盖住了,如果连续三次调用restore()方法,和刚才一样思考就是到了绿色的那个区域(canvas)效果是和你想象的一样,集合图层栈所描述的那样每次调用一次日store()方法都会把这个图层拉出栈顶,然后把下一个图层当作当前要使用的画布

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawColor(Color.parseColor("#e5e5e5"));
    //保存的画布大小为全屏幕大小
    canvas.save();
    canvas.clipRect(new Rect(100, 100, 600, 600));
    canvas.drawColor(Color.GREEN);
    canvas.save();
    canvas.clipRect(new Rect(200, 200, 500, 500));
    canvas.drawColor(Color.BLUE);
    canvas.save();
    canvas.clipRect(new Rect(300, 300, 400, 400));
    canvas.drawColor(Color.BLACK);
}

效果如下:

我现在调用一次restore()效果是这样的:

因为调用了一次restore()方法,就会把蓝色的图层当作新的画布,而调用3次restore()方法效果是这样的

总结下这二个方法的使用

Save():每次调用Save()函数,都会把当前的画布的状态进行保存,然后放入特定的栈中;

restore():每当调用Restore()函数,就会把栈中最顶层的画布状态取出来,并按照这个状态恢复当前的画布,并在这个画布上做画

终于写完了 洗澡睡觉

时间: 2024-08-29 16:35:57

android canvas与图层的关系的相关文章

【转】Android Canvas的save(),saveLayer()和restore()浅谈

Android Canvas的save(),saveLayer()和restore()浅谈 时间:2014-12-04 19:35:22      阅读:1445      评论:0      收藏:0      [点我收藏+] save()  saveLayer()  restore() 1.在自定义控件当中你onMeasure和onLayout的工作做完成以后就该绘制该控件了,有时候需要自己在控件上添加一些修饰来满足需求 复写onDraw(Canvas canvas),其中Canvas就像是

Android Canvas save() restore()

Android Canvas save() restore()

Android canvas clip 参数解释

Android 操作Canvas时,可以对一些区域进行多次的操作(包括与.或.非.异或等),示例代码如下 canvas.save(); canvas.translate(10, 310); canvas.clipRect(0, 0, 60, 60); canvas.clipRect(40, 40, 100, 100, Region.Op.XOR); 第二次的Rect与第一次Rect的异或. drawScene(canvas); canvas.restore(); 最后一个参数有多个选择,分别是:

Android Canvas绘制

public class DrawView extends View { public DrawView(Context context) {  super(context); } @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  /*   * 方法 说明 drawRect 绘制矩形 drawCircle 绘制圆形 drawOval 绘制椭圆 drawPath 绘制任意多边形   * drawLine

【转】Android Canvas绘图详解(图文)

转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡在网上的日子 发表于 2012-12-12 20:29 第 63165 次阅读 Canvas,android 15 Android中使用图形处理引擎,2D部分是android SDK内部自己提供,3D部分是用Open GL ES 1.0.今天我们主要要了解的是2D相关的,如果你想看3D的话那么可以跳

自定义控件三部曲之绘图篇(十四)——Canvas与图层(二)

前言: 有些话说得坦白就会变成感慨有些事总想不开难免有太多无奈这一路走来梦想从未更改相信真心的付出就能够活得精彩把头抬起来拍拍身上的尘埃坚守心底的真爱勇敢相信未来 --巫启贤<相信未来> 系列文章: Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268 一.FLAG的具体意义 1.FLAG概述 有关save系列函数,在canvas中总共有如下几个: public int save() pub

自定义控件三部曲之绘图篇(十三)——Canvas与图层(一)

前言:猛然知道姥姥79了,我好怕,好想哭 系列文章: Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268 在给大家讲解了paint的几个方法之后,我觉得有必要插一篇有关Canvas画布的知识,在开始paint之前,我们讲解了canvas绘图的几篇文章和cavas的save().store()的知识,这篇是对Canvas的一个系统的补充,前几篇文章链接如下:<自定义控件之绘图篇(一):概述及基

Android Canvas Paint绘制文本

字体有三种类型:1,内置基本字体 2,通过基本字体和样式,创建新的Typeface 3,引入外部的ttf文件. 示例代码如下: 1. package com.mike.activity; 2. 3. import android.R; 4. import android.app.Activity; 5. import android.graphics.Bitmap; 6. import android.graphics.Canvas; 7. import android.graphics.Col

Android Canvas的save(),saveLayer()和restore()浅谈

save()  saveLayer()  restore() 1.在自定义控件当中你onMeasure和onLayout的工作做完成以后就该绘制该控件了,有时候需要自己在控件上添加一些修饰来满足需求 复写onDraw(Canvas canvas),其中Canvas就像是一块画布,你自定义控件的样式就是在它上面完成的. Canvas ,Paint等基本概念就不赘述了. 2.下面就直接用demo来解释标题列出的方法先介绍save()和 必须了解的相关知识:http://www.cnblogs.com