美文网首页
Android自定义View(4) 《Canvas基本使用》

Android自定义View(4) 《Canvas基本使用》

作者: 非典型程序猿 | 来源:发表于2021-08-29 20:15 被阅读0次

    概述

    在Android中,我们经常会需要去绘制一些自己需要的控件,所以继承自View的自定义View就产生了。这篇文章主要介绍在View中的重要类,Canvas类的一些基本使用。

    Canvas绘制背景

    Canvas绘制背景主要有几个方法

        /**
         * 使用srcover-porterduff模式,用指定的颜色填充整个画布的位图(限于当前剪辑)
         *
         * @param color the color to draw onto the canvas
         */
        public void drawColor(@ColorInt int color) {
            super.drawColor(color);
        }
    
       /**
         * 使用srcover-porterduff模式,用指定的颜色填充整个画布的位图(限于当前剪辑)
         *
         * @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
         *              class for details about {@code ColorLong}s.
         * @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
         *                                  is invalid or unknown.
         */
        public void drawColor(@ColorLong long color){
            super.drawColor(color, BlendMode.SRC_OVER);
        }
    
       /**
         * 使用指定的颜色和porter duff xfermode填充整个画布的位图(仅限于当前剪辑)。
         *
         * @param color the color to draw onto the canvas
         * @param mode the porter-duff mode to apply to the color
         */
        public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
            super.drawColor(color, mode);
        }
    
       /**
         * 使用指定的颜色和blendmode填充整个画布的位图(仅限于当前剪辑)。
         *
         * @param color the color to draw onto the canvas
         * @param mode the blendmode to apply to the color
         */
        public void drawColor(@ColorInt int color, @NonNull BlendMode mode) {
            super.drawColor(color, mode);
        }
    
      /**
         * 使用指定的颜色和blendmode填充整个画布的位图(仅限于当前剪辑)。
         *
         * @param color the {@code ColorLong} to draw onto the canvas. See the {@link Color}
         *              class for details about {@code ColorLong}s.
         * @param mode the blendmode to apply to the color
         * @throws IllegalArgumentException if the color space encoded in the {@code ColorLong}
         *                                  is invalid or unknown.
         */
        public void drawColor(@ColorLong long color, @NonNull BlendMode mode) {
            super.drawColor(color, mode);
        }
    

    画布的平移

    一般采用下面的方法进行canvas的平移

       /**
         * Preconcat the current matrix with the specified translation
         *
         * @param dx The distance to translate in X
         * @param dy The distance to translate in Y
        */
        public void translate(float dx, float dy) {
            if (dx == 0.0f && dy == 0.0f) return;
            nTranslate(mNativeCanvasWrapper, dx, dy);
        }
    

    这个方法可以将canvas的参考坐标平移,并不是平移之前已经绘制的内容,看下面一个例子大家就明白了,代码步骤是这样

    • 绘制一个矩形
    • 平移画布
    • 再绘制一个矩形
      代码如下
    @Override
        protected void onDraw(Canvas canvas){
            super.onDraw(canvas);
            Log.d(TAG,"onDraw");
            // 设置画笔的宽度
            paint.setStrokeWidth(5f);
            // 设置画笔的颜色
            paint.setColor(Color.RED);
            // 设置画笔的Style
            paint.setStyle(Paint.Style.STROKE);
            // 绘制一个矩形
            canvas.drawRect(rectF,paint);
            // 平移画布
            canvas.translate(100,100);
            // 绘制矩形
            rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
            canvas.drawRect(rectF,paint);
        }
    

    运行结果是这样的


    device-2021-08-29-185700.png

    明白了吧,canvas只是你绘制时的一个图层而已,当你平移之后,并不影响之前已经绘制过的内容,所以在使用平移画布时请记得这点。

    Canvas的裁剪,状态的保存和恢复

    1.画布的裁剪

    在学习裁剪之前,需要先搞清楚一个概念,这里画布的裁剪的意义与我们所理解的裁剪纸张的意义是不一样的,这里的裁剪好比你原本可以在一张完整的纸上进行绘制,裁剪后,就好像你的纸张被一张透明的玻璃盖住,中间你裁剪的部分就是空心的,可以往下面的纸张上继续画东西,其余部分则无法绘制,你只能看到之前绘制的内容,你如果裁剪出是一个圆形,那么你就是在这个圆中绘制你的内容,但是这并不影响显示你之前已经在纸上绘制出来的内容.
    非常重要的点
    裁剪是不可逆的 ! ! !
    裁剪是不可逆的 ! ! !
    裁剪是不可逆的 ! ! !
    所以我们在使用裁剪时如果需要恢复,是必须要结合画布的保存和恢复一起使用的.裁剪使用的方法主要有以下几种
    还要注意一点 使用裁剪时需要关闭硬件加速

    setLayerType(LAYER_TYPE_SOFTWARE,null);
    
    • clipOutRect()系列的函数,主要用来裁剪出一个矩形之外的部分
    • clipRect()系列的函数,主要用来裁剪出一个矩形
    • clipOutPath()系列的函数,主要用来裁剪出一个路径外的部分,一般是封闭的图形
    • clipPath()系列的函数,主要用来裁剪出一个路径内的部分,一般为封闭图形

    2.画布的状态保存与恢复

    • 保存
      int save()
    • 恢复
      void restore()
    • 恢复到指定状态
      void restoreToCount(int saveCount)
      这里我们结合一个具体的例子来进行说明,例子的绘制步骤是这样的
    • 1.给Canvas一个绿色背景
    • 2.保存Canvas状态
    • 3.在中心裁剪出一个矩形
    • 4.在裁剪后的Canvas中加入灰色背景色
    • 5.恢复画布状态
    • 6.在恢复后的Canvas上画一个裁剪范围之外的蓝色的矩形框
      好了我们开始写代码,代码也很简单
    @Override
        protected void onDraw(Canvas canvas){
            super.onDraw(canvas);
            Log.d(TAG,"onDraw");
            // 设置画笔的宽度
            paint.setStrokeWidth(10f);
            // 设置画笔的颜色
            paint.setColor(Color.BLUE);
            // 设置画笔的Style
            paint.setStyle(Paint.Style.STROKE);
    
            // 绘制背景色绿色
            canvas.drawColor(Color.GREEN);
            // 保存此时画布状态
            int saveCount = canvas.save();
            // 在画布中间裁剪出一个矩形
            RectF rectF = new RectF(width/2-300,height/2-150,width/2+300,height/2+150);
            canvas.clipRect(rectF);
            // 绘制灰色背景方便观察
            canvas.drawColor(Color.GRAY);
            // 恢复画布状态,即裁剪之前
            canvas.restoreToCount(saveCount);
            // canvas.restore(); 恢复至上一个保存状态,这里和canvas.restoreToCount(saveCount)效果是一致的,择一调用即可。
            // 恢复后绘制一个矩形
            RectF rectB = new RectF(20,20,width-20,height-20);
            canvas.drawRect(rectB,paint);
        }
    

    运行结果如下


    device-2021-08-29-200319.png

    为了验证我们的Canvas恢复是有效的,我们把恢复的代码注释掉,像这样

            // 恢复画布状态,即裁剪之前
            // canvas.restoreToCount(saveCount);
    

    运行后变成了这样


    device-2021-08-29-200553.png

    我们最后绘制的蓝色矩形框没了,所以裁剪后在裁剪范围外绘制的内容是无效的,但是裁剪前绘制的内容是不影响显示的,所以这样可以理解裁剪时类似透明玻璃层的概念了吧

    总结

    Canvas的背景绘制,平移,状态保存和恢复就整理到这里了,下篇总结一下视图动画~

    相关文章

      网友评论

          本文标题:Android自定义View(4) 《Canvas基本使用》

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