美文网首页
Canvas绘图基础

Canvas绘图基础

作者: 竖起大拇指 | 来源:发表于2020-09-16 17:35 被阅读0次

    Canvas坐标系和绘图坐标系

    Canvas绘图中牵扯到两种坐标系:Canvas坐标系与绘图坐标系。

    • Canvas坐标系
      Canvas坐标系值的是Canvas本身的坐标系,Canvas坐标系有且只有一个,且是唯一不变的,其坐标原点在View的左上角,从坐标原点向右为X轴的正半轴,从坐标原点向下为Y轴的正半轴。
    • 绘图坐标系
      Canvas的drawXXX方法中传入的各种坐标系指的都是绘图坐标系中的坐标,而非Canvas坐标系中的坐标。默认情况下,绘图坐标系与Canvas坐标系完全重合,即初始状态下,绘图坐标系的坐标原点也在View的左上角,从原点向右为X轴正半轴,从原点向下为Y轴正半轴。但不同于Canvas坐标系,绘图坐标系并不是一成不变的,可以通过调用Canvas的translate方法平移坐标系,可以通过Canvas的rotate方法旋转坐标系,还可以通过Canvas的scale方法缩放坐标系,而且需要注意的是,translate,rotate,scale的操作都是基于当前绘图坐标系的,而不是基于Canvas坐标系,一旦通过以上方法对坐标系进行操作之后,当前绘图坐标系就变化了,以后绘图都是基于更新的绘图坐标系了。也就是说,真正对我们绘图有用的是绘图坐标系而非Canvas坐标系。
      为了更好的理解绘图坐标系,请看如下代码:
    /**
     * Created by maozonghong
     * on 2020/9/16
     */
    class AxisView @JvmOverloads constructor(context: Context,attr:AttributeSet?) : View(context,attr) {
    
        var paint= Paint(Paint.ANTI_ALIAS_FLAG)
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            var canvasWidth=canvas?.width?:0
            var canvasHeight=canvas?.height?:0
    
            paint.style=Paint.Style.STROKE
            paint.strokeCap=Paint.Cap.ROUND
            paint.strokeWidth=6*context.resources.displayMetrics.density
    
            //黄色画X轴
            paint.color=-0x33bc
            //绘制X轴
            canvas?.drawLine(0f,0f,canvasWidth.toFloat(),0f,paint)
    
            //蓝色画Y轴
            paint.color=-0x995501
            //绘制Y轴
            canvas?.drawLine(0f,0f,0f,canvasHeight.toFloat(),paint)
    
    
            //对坐标系平移之后 第二次绘制坐标轴
            canvas?.translate(canvasWidth/4f,canvasWidth/4f) //坐标系右下角平移
            paint.color=-0x33bc
            //绘制X轴
            canvas?.drawLine(0f,0f,canvasWidth.toFloat(),0f,paint)
            paint.color=-0x995501
            //绘制Y轴
            canvas?.drawLine(0f,0f,0f,canvasHeight.toFloat(),paint)
    
    
            //再次平移坐标系并在此基础上旋转坐标系,第三次绘制坐标轴
            canvas?.translate(canvasWidth/4f,canvasWidth/4f) //在上次平移的基础上 再把坐标系向右下角平移
            //基于当前绘图坐标系的原点旋转
            canvas?.rotate(90f)
    
            paint.color=-0x33bc
            //绘制X轴
            canvas?.drawLine(0f,0f,canvasWidth.toFloat(),0f,paint)
            paint.color=-0x995501
            //绘制Y轴
            canvas?.drawLine(0f,0f,0f,canvasHeight.toFloat(),paint)
    
    
        }
    }
    
    

    效果如下所示:


    device-2020-09-16-133843.png

    说明:
    第一次绘制绘图坐标系时,绘图坐标系默认情况下和Canvas坐标系重合,所以绘制出的坐标系紧贴View的上侧和左侧;
    第二次首先将坐标轴向右下角平移了一段距离,然后绘制出的坐标系也就整体向右下角平移了;
    第三次再次向右下角平移,并旋转了90°,即最后的绘图坐标系。

    drawARGB

    Canvas中的drawARGB可以用来对整个Canvas以某种统一的颜色整体绘制,四个参数分别时Alpha,Red,Green,Blue,取值都是0-255。使用代码如下:

    override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            //设置背景色
            canvas?.drawARGB(255, 139, 197, 186)
    }
    

    效果如下:


    device-2020-09-16-134743.png

    drawText

    Canvas中用drawText方法绘制文字,代码如下:

    override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            paint.textSize=25f
            var textHeight=50f
    
            var canvasWidth=canvas?.width?:0
            var halfCanvasWidth=canvasWidth/2
            var translateY=textHeight
    
            //绘制正常文本
            canvas?.save()
            canvas?.translate(0f,translateY)
            canvas?.drawText("正常绘制文本",0f,0f,paint)
            canvas?.restore()
    
            translateY+=textHeight*2
            //设置字体颜色为蓝色
            paint.color=-0x995501
    
            canvas?.save()
            canvas?.translate(0f,translateY)
            canvas?.drawText("绘制蓝色文本",0f,0f,paint)
            canvas?.restore()
    
            paint.color= Color.BLACK
    
            translateY+=textHeight*2
    
            //设置左对齐
            paint.textAlign=Paint.Align.LEFT
    
            paint.strokeWidth=10f
    
            canvas?.save()
            canvas?.translate(halfCanvasWidth.toFloat(),translateY)
            canvas?.drawText("左对齐文本",0f,0f,paint)
            canvas?.restore()
    
            translateY+=textHeight*2
    
            //设置居中对齐
            paint.textAlign=Paint.Align.CENTER
            canvas?.save()
            canvas?.translate(halfCanvasWidth.toFloat(),translateY)
            canvas?.drawPoint(0f,0f,paint)
            canvas?.drawText("居中对齐文本",0f,0f,paint)
            canvas?.restore()
    
            translateY+=textHeight*2
            //设置向右对齐
            paint.textAlign=Paint.Align.RIGHT
    
            canvas?.save()
            canvas?.translate(halfCanvasWidth.toFloat(),translateY)
            canvas?.drawPoint(0f,0f,paint)
            canvas?.drawText("右对齐文本",0f,0f,paint)
            canvas?.restore()
    
            paint.textAlign=Paint.Align.LEFT //重新设置为左对齐
    
            translateY+=textHeight*2
    
            //设置下划线
            paint.isUnderlineText=true
            canvas?.save()
            canvas?.translate(0f,translateY)
            canvas?.drawText("下划线文本",0f,0f,paint)
            canvas?.restore()
    
            //重新设置为没有下划线
            paint.isUnderlineText=false
            translateY+=textHeight*2
    
            //绘制加粗文字
            paint.isFakeBoldText=true
            canvas?.save()
            canvas?.translate(0f,translateY)
            canvas?.drawText("粗体文本",0f,0f,paint)
            canvas?.restore()
    
            //重新将画笔设置为非粗体状态
            paint.isFakeBoldText=false
    
            translateY+=textHeight*2
    
            //文本绕绘制起点顺时针旋转
            canvas?.save()
            canvas?.translate(0f,translateY)
            canvas?.rotate(20f)
            canvas?.drawText("文本绕绘制起点旋转20°",0f,0f,paint)
            canvas?.restore()
    
        }
    

    效果如下:


    device-2020-09-16-143726.png

    说明:

    • 我们在上面的代码中将canvas.translate()和canvas.rotate()放到了canvas.save()和canvas.restore()之间,这样做的好处是,在canvas.save()调用时,将当前坐标系保存下来,将当前坐标系的矩阵Matrix入栈保存,然后通过translate或rotate等对坐标系进行变换,然后进行绘图,绘图完成后,我们通过调用canvas.restore()将之前保存的Matrix出栈,这样就会将当前绘图坐标系恢复到了canvas.save()执行的时候状态。
    • 通过调用paint.setTextAlign()设置文本的对齐方式,该对齐方式是相对于绘制文本时的画笔的坐标来说的。在drawText()方法执行时,需要传入一个x和y坐标,假设该点为P点,P点表示我们从P点绘制文本。当对齐方式为Paint.Align.LEFT时,绘制的文本以P点为基准向左对齐,这是默认的对齐方式;当对齐方式为Paint.Align.CENTER时,绘制的文本以P点为基准居中对齐;当对齐方式为Paint.Algin.RIGHT时,绘制的文本以P点为基准向右对齐。

    drawPoint

    Canvas中用drawPoint方法绘制点,代码如下:

    override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            var canvasWidth=canvas?.width?:0
            var canvasHeight=canvas?.height?:0
            var x=canvasWidth/2
            var deltaY=canvasHeight/3
            var y=deltaY/2
    
            paint.color=-0x995501
            paint.strokeWidth=50*context.resources.displayMetrics.density
    
            //绘制Cap为Butt的点
            paint.strokeCap=Paint.Cap.BUTT
            canvas?.drawPoint(x.toFloat(),y.toFloat(),paint)
    
            //绘制Cap为ROUND的点
            canvas?.translate(0f,deltaY.toFloat())
            paint.strokeCap=Paint.Cap.ROUND
            canvas?.drawPoint(x.toFloat(),y.toFloat(),paint)
    
            //绘制Cap为SQUARE的点
            canvas?.translate(0f,deltaY.toFloat())
            paint.strokeCap=Paint.Cap.SQUARE
            canvas?.drawPoint(x.toFloat(),y.toFloat(),paint)
    
        }
    

    效果如下:


    device-2020-09-16-150942.png

    说明:

    • Paint的setStrokeWidth方法可以控制所画线的宽度,通过Paint的getStrokeWidth方法可以得到所画线的宽度,在默认情况下,线宽为0。其实strokeWidth不仅对画线有影响,对画点也有影响,由于默认的线宽是0,所以默认情况下调用drawPoint方法无法在Canvas上画点。为了让大家清楚地看到所画的点,我用Paint的setStrokeWidth设置了一个比较大的线宽,这样我们看到的点也就比较大。
    • 默认情况下Paint的getStrokeCap的返回值是Paint.Cap.BUTT,默认画出来的点就是一个正方形,上图第一个点即是用BUTT作为帽端画的。

    drawLine

    Canvas通过drawLine方法绘制一条线,通过drawLines方法绘制多段线。

    // 画一条直线
    // 在坐标(100,200),(700,200)之间绘制一条直线
       canvas.drawLine(100,200,700,200,mPaint1);
    
    // 绘制一组线
    // 在坐标(400,500),(500,500)之间绘制直线1
    // 在坐标(400,600),(500,600)之间绘制直线2
            canvas.drawLines(new float[]{
                    400,500,500,500,
                    400,600,500,600
            },mPaint2);
        }
    

    drawRect

    Canvas通过drawRect方法绘制矩形,使用代码如下:

    override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            var canvasWidth=canvas?.width?:0
            var canvasHeight=canvas?.height?:0
    
            var left1=10f
            var top1=10f
            var right1=canvasWidth/3f
            var bottom1=canvasHeight/3f
            paint.color=-0x995501
            canvas?.drawRect(left1,top1,right1,bottom1,paint)
    
            paint.color=-0x33bc
            var left2=canvasWidth/3*2f
            var top2=10f
            var right2=canvasWidth-10f
            var bottom2=canvasHeight/3f
    
            canvas?.drawRect(left2,top2,right2,bottom2,paint)
        }
    

    界面如下所示:

    device-2020-09-16-152948.png

    left和right表示矩形的左边和右边分别到绘图坐标系y轴正半轴的距离,top和bottom表示矩形的上边和下边分别到绘图坐标系x轴正半轴的距离。

    drawCircle

    Canvas中用drawCircle方法绘制圆形,使用代码如下:

      override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            paint.color=-0x995501
            //默认绘图为填充模式
            paint.style=Paint.Style.FILL
    
            var canvasWidth=canvas?.width?:0
            var canvasHeight=canvas?.height?:0
    
            var halfCanvasWidth=canvasWidth/2f
    
            var translateY=canvasHeight/4f
            var R=translateY/2f
    
            //绘制圆
            canvas?.translate(0f,translateY/4f)
    
            canvas?.drawCircle(halfCanvasWidth,R,R,paint)
    
            //绘制两个圆 形成圆环
            //1.首先绘制大圆
            canvas?.translate(0f,translateY+translateY/4f)
            canvas?.drawCircle(halfCanvasWidth,R,R,paint)
            //2.然后绘制小圆 让小圆覆盖大圆 形成圆环效果
            var r=R*0.75f
    
            paint.color= Color.WHITE
            canvas?.drawCircle(halfCanvasWidth,R,r,paint)
    
    
            //通过线条绘图模式绘制圆环
            canvas?.translate(0f,translateY+translateY/4f)
            paint.color=-0x995501
            paint.style=Paint.Style.STROKE
            var strokeWidth=R*0.25f
            paint.strokeWidth=strokeWidth
            canvas?.drawCircle(halfCanvasWidth,R,R,paint)
        }
    

    效果如下:


    device-2020-09-16-162106.png

    代码说明:

    • 我们可以通过绘制两个圆面的方式绘制出圆环的效果。首先将画笔设置为某一颜色,且style设置为FILL状态,通过drawCircle绘制一个大的圆面;然后将画笔Paint的颜色改为白色或其他颜色,并减小半径再次通过drawCircle绘制一个小圆,这样就用小圆遮盖了大圆的一部分,未遮盖的部分便自然形成了圆环的效果,如上图中的第二个图形所示。

    • 除了上述方法,我们还有一种办法绘制圆环的效果。我们首先将画笔Paint的style设置为STROKE模式,表示画笔处于画线条模式,而非填充模式。然后为了让圆环比较明显有一定的宽度,我们需要调用Paint的setStrokeWidth方法设置线宽。最后调用drawCircle方法绘制出宽度比较大的圆的轮廓线,也就形成了圆环效果,如上图中的最后一个图形所示。此处需要说明的是,当我们用STROKE模式画圆时,轮廓线是以实际圆的边界为分界线分别向内向外扩充1/2的线宽的距离,比如圆的半径是100,线宽是20,那么在STROKE模式下绘制出的圆环效果相当于半径为110的大圆和半径为90的小圆形成的效果,100 + 20 / 2 = 110, 100 - 20/2 = 90。

    drawOval

    Canvas中提供了drawOval方法绘制椭圆,其使用代码如下所示 :

     override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            var canvasWidth=canvas?.width?:0
    
            var canvasHeight=canvas?.height?:0
    
            var quarter=canvasHeight/4f
    
            var density=context.resources.displayMetrics.density
    
            var left=10*density
    
            var top=0f
    
            var right=canvasWidth-left
    
            var bottom=quarter
    
            var rectF= RectF(left,top,right,bottom)
    
            //绘制椭圆形轮廓线
            paint.style=Paint.Style.STROKE
            paint.strokeWidth=2*density
            paint.color=-0x995501
            canvas?.translate(0f,quarter/4f)
            canvas?.drawOval(rectF,paint)
    
            //绘制椭圆形填充面
            paint.style=Paint.Style.FILL
            canvas?.translate(0f,quarter+quarter/4f)
            canvas?.drawOval(rectF,paint)
    
            //画两个椭圆,形成轮廓线和填充色不同的效果
            canvas?.translate(0f,quarter+quarter/4f)
            paint.style= Paint.Style.FILL
            canvas?.drawOval(rectF,paint)
    
            paint.style= Paint.Style.STROKE
            paint.color= Color.GREEN
            canvas?.drawOval(rectF,paint)
    
        }
    
    

    效果如下所示:


    device-2020-09-16-163829.png

    下面对以上代码进行说明:

    1. 其方法签名是public void drawOval (RectF oval, Paint paint),RectF有四个字段,分别是left、top、right、bottom,
      这四个值对应了椭圆的左、上、右、下四个点到相应坐标轴的距离,具体来说,left和right表示椭圆的最左侧的点和最右侧的点到绘图坐标系的y轴的距离,top和bottom表示椭圆的最顶部的点和最底部的点到绘图坐标系的x轴的距离,这四个值就决定了椭圆的形状,right与left的差值即为椭圆的长轴,bottom与top的差值即为椭圆的短轴,如下图所示:


      这里写图片描述
    2. 通过Paint的setStyle方法将画笔的style设置成STROKE,即画线条模式,这种情况下,用画笔画出来的是椭圆的轮廓线,而非填充面,如上图中的第一个图形所示。

    3. 当将画笔Paint的style设置为FILL时,即填充模式,这种情况下,用画笔画出来的是椭圆的填充面,如上图中的第二个图形所示。

    4. 如果我们想绘制带有其他颜色轮廓线的椭圆面,我们需要绘制两个椭圆。首先以FILL模式画一个椭圆的填充面,然后更改画笔颜色,以STROKE模式画椭圆的轮廓线,如上图中的最后一个图形所示。这样从外观上看,好像是椭圆面与椭圆的轮廓线颜色不同。

    drawArc

    Canvas中提供了drawArc方法用于绘制弧,这里的弧指两种:弧面和弧线,弧面即用弧围成的填充面,弧线即为弧面的轮廓线。其使用代码如下:

    override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            var density=context.resources.displayMetrics.density
            var canvasWidth=canvas?.width?:0
            var canvasHeight=canvas?.height?:0
            var ovalHeight=canvasHeight/6f
            var left=10*density
            var top=0f
            var right=canvasWidth-left
            var bottom=ovalHeight
    
            var rectF= RectF(left,top,right,bottom)
    
            //设置线宽
            paint.strokeWidth=2*density
            paint.color=-0x995501
            //默认设置画笔颜色为填充颜色
            paint.style=Paint.Style.FILL
    
            //绘制用drawArc绘制完整的椭圆
            canvas?.translate(0f,ovalHeight/5f)
            canvas?.drawArc(rectF,0f,360f,true,paint)
    
            //绘制椭圆的四分之一 起点是钟表的3点位置 从三点绘制到六点的位置
            canvas?.translate(0f,ovalHeight+ovalHeight/5f)
            canvas?.drawArc(rectF,0f,90f,true,paint)
    
            //绘制椭圆的四分之一,将userCenter设置为false
            canvas?.translate(0f,ovalHeight+ovalHeight/5f)
            canvas?.drawArc(rectF,0f,90f,false,paint)
    
            //绘制椭圆的四分之一 只绘制轮廓线
            paint.style=Paint.Style.STROKE
            canvas?.translate(0f,ovalHeight+ovalHeight/5f)
            canvas?.drawArc(rectF,0f,90f,true,paint)
    
            //绘制带有轮廓线的椭圆的四分之一
            //1.先绘制椭圆的填充部分
            paint.style= Paint.Style.FILL
            canvas?.translate(0f,ovalHeight+ovalHeight/5f)
            canvas?.drawArc(rectF,0f,90f,true,paint)
            //2.再绘制椭圆的轮廓线部分
            paint.style= Paint.Style.STROKE
            paint.color= Color.GREEN
            canvas?.drawArc(rectF,0f,90f,true,paint)
    
    
        }
    

    效果如下:


    device-2020-09-16-165828.png

    说明:

    • 用drawArc画的弧指的是椭圆弧,即椭圆的一部分。当然,如果椭圆的长轴和和短轴相等,这时候我们就可以用drawArc方法绘制圆弧。其方法签名是:

    public void drawArc (RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)

    oval是RecF类型的对象,其定义了椭圆的形状。 startAngle指的是绘制的起始角度,钟表的3点位置对应着0度,如果传入的startAngle小于0或者大于等于360,那么用startAngle对360进行取模后作为起始绘制角度。 sweepAngle指的是从startAngle开始沿着钟表的顺时针方向旋转扫过的角度。如果sweepAngle大于等于360,那么会绘制完整的椭圆弧。如果sweepAngle小于0,那么会用sweepAngle对360进行取模后作为扫过的角度。 useCenter是个boolean值,如果为true,表示在绘制完弧之后,用椭圆的中心点连接弧上的起点和终点以闭合弧;如果值为false,表示在绘制完弧之后,弧的起点和终点直接连接,不经过椭圆的中心点。

    • 在代码中我们一开始设置的Paint的style为FILL,即填充模式。通过上面的描述我们知道,drawOval方法可以看做是drawArc方法的一种特例。如果在drawArc方法中sweepAngle为360,无论startAngle为多少,drawArc都会绘制一个椭圆,如上图中第一个图形,我们用canvas.drawArc(rectF, 0, 360, true, paint)绘制了一个完整的椭圆,就像用drawOval画出的那样。

    • 当我们调用方法canvas.drawArc(rectF, 0, 90, true, paint)时, 我们指定了起始角度为0,然后顺时针绘制90度,即我们会绘制从3点到6点这90度的弧,如上图中第二个图形所示,我们绘制了一个椭圆的右下角的四分之一的弧面,需要注意的是我们此处设置的useCenter为true,所以弧上的起点(3点位置)和终点(6点位置)都和椭圆的中心连接了形成了。

    • 当我们调用方法canvas.drawArc(rectF, 0, 90, false, paint)时,我们还是绘制椭圆右下角的弧面,不过这次我们将useCenter设置成了false,如上图中的第三个图形所示,弧上的起点(3点位置)和终点(6点位置)直接相连闭合了,而没有经过椭圆的中心点。

    • 上面介绍到的绘图都是在画笔Paint处于FILL状态下绘制的。我们可以通过paint.setStyle(Paint.Style.STROKE)方法将画笔的style改为STROKE,即绘制线条模式。然后我们再次执行canvas.drawArc(rectF, 0, 90, true, paint),初始角度为0,扫过90度的区域,useCenter为true,绘制的效果见上图中第四个图形,此时我们只绘制了椭圆的轮廓线。需要注意的,由于Paint默认的线宽为0,所以在绘制之前要确保掉用过Paint.setStrokeWidth()方法以设置画笔的线宽。

    • 如果我们想绘制出带有其他颜色轮廓线的弧面时,该怎么办呢?我们可以分两步完成:首先,将画笔Paint的style设置为FILL模式,通过drawArc方法绘制出弧面。然后,将画笔Paint的style设置为STROKE模式,并通过paint的setColor()方法改变画笔的颜色,最后drawArc方法绘制出弧线。这样我们就能绘制出带有其他颜色轮廓线的弧面了,如上图中最后一个图形所示。

    drawBitmap

    Canvas中提供了drawBitmap方法用于绘制Bitmap,其使用代码如下所示:

     override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            //如果bitmap不存在,那么就不执行下面的绘制代码
    
            if (bitmap == null) {
                return
            }
    
            //直接完全绘制Bitmap
    
            canvas?.drawBitmap(bitmap, 0f, 0f, paint)
    
            //绘制Bitmap的一部分,并对其拉伸
            //srcRect定义了要绘制Bitmap的哪一部分
    
            val srcRect = Rect()
            srcRect.left = 0
            srcRect.right = bitmap.width
            srcRect.top = 0
            srcRect.bottom = (0.33f * bitmap.height).toInt()
            val radio= (srcRect.bottom - srcRect.top) / bitmap.width
            
            //dstRecF定义了要将绘制的Bitmap拉伸到哪里
            val dstRecF = RectF()
            dstRecF.left = 0f
            dstRecF.right = canvas?.width?.toFloat()?:0f
            dstRecF.top = bitmap.height.toFloat()
            val dstHeight = (dstRecF.right - dstRecF.left) * radio
            dstRecF.bottom = dstRecF.top + dstHeight
            canvas?.drawBitmap(bitmap, srcRect, dstRecF, paint)
        }
    
    
    • Canvas的drawBitmap有多个重载方法,最简单的方法签名是:

    public void drawBitmap (Bitmap bitmap, float left, float top, Paint paint)

    该方法除了传入bitmap对象外,还需要传入left和top,left和top组成了一个坐标,决定了在Canvas中从哪个地方绘制Bitmap。在我们的代码中,left和top都设置为0,所以我们就在Canvas的左上角绘制了bitmap。

    • drawBitmap还有一个比较实用的方法,其方法签名是:

    public void drawBitmap (Bitmap bitmap, Rect src, Rect dst, Paint paint)

    该方法有两个功能:1.只绘制原有bitmap对象的一部分,2.还可以将要绘制的bitmap缩放到指定的区域。

    • 只绘制原有bitmap对象的一部分
      我们知道Bitmap是一个矩形,其是有宽度和高度的,也就说以bitmap对象本身作为坐标系(原点在bitmap左上角),我们可以构建一个Rect对象,如果满足left为0,top为0,right为bitmap的宽度,bottom为bitmap的高度,那么就说名我们要绘制整个Bitmap。但是有时候我们只想绘制Bitmap的一部分,例如我们上面的图中所示,我们想只绘制Android图像的头部区域怎么办呢?办法是我们构建一个Rect对象,定义我们要绘制Bitmap的哪些部位。
      比如我们通过代码srcRect.bottom = (int)(0.33 * bitmap.getHeight())指定了我们只绘制bitmap对象头部1/3的位置,即Android图像的头部,这样我们用该指定的srcRect绘制bitmap时只绘制了其头部位置。需要特别注意的是,srcRect中left、top、right、bottom的值都是以Bitmap本身的局部坐标系为基础的。

    • 将要绘制的bitmap缩放到指定的区域
      有时候我们需要将原有的bitmap进行放大或缩小,如上图所示,我们将原有图片放大了,这怎么做呢?我们需要指定RectF类型的参数dstRectF,以便告诉Android将srcRect中定义的bitmap缩放到哪里。即Android会将srcRect中定义的bitmap缩放到dstRectF区域范围内。需要注意的是,此处的dstRecF是绘图坐标系中的坐标,不是Bitmap本身的局部坐标系。我们在代码中保证了dstRecF的长宽比与srcRect中的长宽比相同,这样不会导致图片长宽比例变形,效果见上图中的第二个放大的图形。

    • 此处有一点需要说明,在绘图结束退出Activity的时候,我们需要调用bitmap的recyle()方法,防止内存泄露,本程序在onDestroy()方法中执行了该方法。

    相关文章

      网友评论

          本文标题:Canvas绘图基础

          本文链接:https://www.haomeiwen.com/subject/glucyktx.html