View 自定义控件 onDraw()绘图描述 Paint和Canvas

我们知道,onDraw()中,是进行绘制的地方。Canvas 和 Paint 就像我们平时画画所需要用的画笔和画纸,Paint 是画笔,我们可以设置画笔的颜色,画笔的线条的宽、透明,是否毛边等等,Canvas 是画布,比如可以提供不同颜色的画布,可以在画布上用笔画出矩形、圆形、弧线、三角形、图片、文字等等。

public class DrawView extends View {

    Paint mPaint = new Paint();

    public DrawView(Context context) {
        this(context, null);
    }

    public DrawView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        mPaint.setAntiAlias(true);
        //设置画笔宽度
        mPaint.setStrokeWidth(5);
        //设置画笔颜色
        mPaint.setColor(Color.GRAY);
        //设置画笔样式
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.BLUE);
        canvas.drawCircle(300,300,100,paint);
    }

}

这样,整个view的背景都是蓝色,在其上面画了一个圆,圆心距离其父容器的左上角距离x轴和y轴都是300px,圆的半径为100px。这只是一个例子,在 Canvas 中,例子很多

1)  drawArc():绘制圆弧;
2)  drawBitmap():绘制Bitmap图像;
3)  drawCircle():绘制圆圈;
4)  drawLine():绘制线条;
5)  drawOval():绘制椭圆;
6)  drawPath():绘制Path路径;
7)  drawPicture():绘制Picture图片;
8)  drawRect():绘制矩形;
9)  drawRoundRect():绘制圆角矩形;
10) drawText():绘制文本;
11) drawVertices():绘制顶点。

这上面的都简单,参考着api就可以使用了。

这里提一下drawText的绘制,这个是绘制文案的,我们可以横着绘制文字、竖着绘制,还可以沿着圆绘制,这个api里也有说明,现在说一下横着绘制文案时,文字的高度问题,

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //标准线,先绘制一条线出来,等会你就会发现一个非常不可思议的事情
       canvas.drawLine(100,100,1000,100,mPaint);
       canvas.drawText("gaoxiaowomenshirenzhende....”,200,100,mPaint);
    }

按理来说,文字应该在横线下面,紧贴着横线,但事实是,像abc这样的字母是在横线的上面,但像g这样的字母,g的下面已经突破横线了,这是怎么回事呢?这就是四线格与基线了。
drawText() 函数是绘制文本最常用的方法,开始以为(x,y) 就是要绘制的文字的左上角的坐标,其实不是,我们传进去的(x,y)其中的 y 表示的是上图中基线的位置,x也不是文案开始的位置。 paint.setTextAlign(Paint.Align.XXX); 这个函数是用来设置文字的对齐方式的,它的 取值有三个,左对齐(Panit.Align.LEFT)、居中对齐(Paint.Align.CENTER)和 右对齐(Paint.Align.RIGHT )。  当为左对齐时,x 指代的就是文案要绘制的 X 轴的坐标,(x,y)就是要绘制的文本的起始位置;居中对齐时,x 指代的是一个相对距离,是文案会以x为中点,x为文案的居中点;右对齐也同理,x 指的是文案的结尾处的位置的坐标。Y轴的值为基准线,基本可以理解为是文案文字底部所在的坐标,细扣的话,还有 ascent 线、 descent 线、top 线、bottom 线,我们平时一般用不到这么细致。

Canvas还有其他几个稍微不同的方法

1)  canvas.save():把当前绘制的图像保存起来,让后续的操作相当于是在一个新图层上绘制;
2)  canvas.restore():把当前画布调整到上一个save()之前的状态;
3)  canvas.translate(dx, dy):把当前画布的原点移到(dx, dy)点,后续操作都以(dx, dy)点作为参照;
4)  canvas.scale(x, y):将当前画布在水平方向上缩放x倍,竖直方向上缩放y倍;
5)  canvas.rotate(angle):将当前画布顺时针旋转angle度。

先说 3) translate(dx, dy),这个意思是画布的原点位移,画布的原点默认是左上角,
        Paint paint = new Paint();
        paint.setColor(Color.YELLOW);
        canvas.drawRect(new Rect(0, 0, 200, 200), paint);
意思是从左上角开始,画一个黄颜色的矩形,宽为200,高为200;如果我们使用了translate(dx, dy),那么
        Paint paint = new Paint();
        canvas.translate(200, 200);
        paint.setColor(Color.YELLOW);
        canvas.drawRect(new Rect(0, 0, 200, 200), paint);
这个矩形不变,但是往右和往下都位移了200,也就是说原先左上角顶点坐标由(0,0)变为(200,200),后续再画其他的图形,顶点也是以(200,200)为坐标,而非是原始的(0,0)坐标,除非执行canvas.translate(-200, -200); 这样才会回到原点(0,0)。

先讲3) ,然后再讲 1)和2) 就比较好理解了。save() 和 restore() 是成对出现的,restore()不能比save()调用的次数多。还是上面的例子,
        Paint paint = new Paint();
        canvas.translate(200, 200);
        paint.setColor(Color.YELLOW);
        canvas.drawRect(new Rect(0, 0, 200, 200), paint);
        paint.setColor(Color.RED);
        canvas.drawRect(new Rect(0, 0, 50, 50), paint);
上面会画出两个正方形,但是,左上角的顶点都是(200, 200),我们如果想第二个小的红正方形的顶点是(0, 0),怎么办?除了上面的反向位移,另外一个方法就是save()和restore()了,比如一开始保存一下画布,相当于单独开辟了一层空间,绘制完后,再还原一下,恢复到上一层,此时重新绘制的都是新开的一层,原先的一层已保存
        canvas.save();
        Paint paint = new Paint();
        canvas.translate(200, 200);
        paint.setColor(Color.YELLOW);
        canvas.drawRect(new Rect(0, 0, 200, 200), paint);
        canvas.restore();
        paint.setColor(Color.RED);
        canvas.drawRect(new Rect(0, 0, 50, 50), paint);
这样,也达到了需求。

4)的意思是缩放,如果是5,则是变为原先的五倍;如果是0.5,则是变为原先的0.5倍,即缩小一半。这个变化是指画布的缩放,一旦执行这个操作,后续的在同一层的画布上,所有的绘制都按照这个比例扩大。
        Paint paint = new Paint();
        canvas.scale(0.5f, 0.5f);
        paint.setColor(Color.YELLOW);
        canvas.drawRect(new Rect(0, 0, 200, 200), paint);
这个画布缩放了0.5倍,则原先黄色的正方形边长了200,此时画出来了边长缩小一半,变为了100。
    canvas.scale(sx, sy, px, py) 这个方法的意思是缩放时加了个位移,我们看一下源码

    public final void scale(float sx, float sy, float px, float py) {
        translate(px, py);
        scale(sx, sy);
        translate(-px, -py);
    }
意思是先位移了px, py,然后进行了缩放,注意看,是缩放后,然后又反向位移。如果缩放的sx 和 sy 都为1,那么没影响。但如果缩放为0.3,位移为300,也就是说,canvas.scale(0.3f, 0.3f, 300, 300); 此时按照代码分析,先是顶点由(0,0)变为(300,300);这时候进行了缩放,倍数为0.3;这时候又要位移了,数值为-300,但前一步我们缩放为原先的0.3倍,也就是说位移值为 -300 * 0.3 = -90,此时顶点由(300,300)变为了(210,210),这一点容易迷惑人,并不是移动后,有原封不动的回到了原点。

5) 旋转,这个好理解,正数是顺时针旋转,负数是逆时针旋转,注意,旋转的是整个画布,而不是图片旋转了,默认的旋转中心点坐标是(0,0)。rotate(angle, px, py) 的原理和 4) 中的多参数的缩放一个道理,看看它的源码
    public final void rotate(float degrees, float px, float py) {
        translate(px, py);
        rotate(degrees);
        translate(-px, -py);
    }
这个是可以指定旋转中心点的坐标,比如 canvas.rotate(30, 300, 300); 则是以(300, 300)为中心点旋转的,旋转后,会还原旋转点的坐标为(0,0)。
 

猜你喜欢

转载自blog.csdn.net/Deaht_Huimie/article/details/89004530