美文网首页
Android自定义View进阶:绘制基本形状(一)

Android自定义View进阶:绘制基本形状(一)

作者: 冉冉升起的小太阳 | 来源:发表于2017-05-10 15:43 被阅读187次

    Android自定义View基础:坐标系
    Android自定义View基础:角度弧度
    Android自定义View进阶:分类与流程

    1.Canvas的常用操作速查表

    API

    2.Canvas详解

    创建画笔:

    //创建画笔
    private Paint paint = new Paint();
    private void initPaint(){
            mPaint.setColor(Color.BLACK);       //设置画笔颜色
            mPaint.setStyle(Paint.Style.FILL);  //设置画笔模式为填充
            mPaint.setStrokeWidth(10f);         //设置画笔宽度为10px
    }
    
    //构造函数
      public PaintView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPaint();
        }
    

    绘制点:

       canvas.drawPoint(200, 200, mPaint);     //在坐标(200,200)位置绘制一个点
            canvas.drawPoints(new float[]{          //绘制一组点,坐标位置由float数组指定
                    500,500,
                    500,600,
                    500,700
            },mPaint);
    
    图例

    绘制直线:

    //绘制直线需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:
        canvas.drawLine(300,300,500,600,mPaint);    // 在坐标(300,300)(500,600)之间绘制一条直线
            canvas.drawLines(new float[]{               // 绘制一组线 每四数字(两个点的坐标)确定一条线
                    100,200,200,200,
                    100,300,200,300
            },mPaint);
    

    绘制矩形:
    确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。
    关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。 其余两种是先将矩形封装为Rect或RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:

        // 第一种
        canvas.drawRect(100,100,800,400,mPaint);
    
        // 第二种
        Rect rect = new Rect(100,100,800,400);
        canvas.drawRect(rect,mPaint);
    
        // 第三种
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawRect(rectF,mPaint);
    

    以上三种方法所绘制出来的结果是完全一样的。


    看到这里,相信很多观众会产生一个疑问,为什么会有Rect和RectF两种?两者有什么区别吗?
    答案当然是存在区别的,两者最大的区别就是精度不同,Rect是int(整形)的,而RectF是float(单精度浮点型)的。除了精度不同,两种提供的方法也稍微存在差别,在这里我们暂时无需关注,想了解更多参见官方文档 RectRectF
    绘制圆角矩形:
    绘制圆角矩形也提供了两种重载方式,如下:
    // 第一种
    RectF rectF = new RectF(100,100,800,400);
    canvas.drawRoundRect(rectF,30,30,mPaint);
        // 第二种
        canvas.drawRoundRect(100,100,800,400,30,30,mPaint);
    

    上面两种方法绘制效果也是一样的,但鉴于第二种方法在API21的时候才添加上,所以我们一般使用的都是第一种。


    下面简单解析一下圆角矩形的几个必要的参数的意思。
    很明显可以看出,第二种方法前四个参数和第一种方法的RectF作用是一样的,都是为了确定一个矩形,最后一个参数Paint是画笔,无需多说,与矩形相比,圆角矩形多出来了两个参数rx 和 ry,这两个参数是干什么的呢?
    稍微分析一下,既然是圆角矩形,他的角肯定是圆弧(圆形的一部分),我们一般用什么确定一个圆形呢?
    答案是圆心 和 半径,其中圆心用于确定位置,而半径用于确定大小
    由于矩形位置已经确定,所以其边角位置也是确定的,那么确定位置的参数就可以省略,只需要用半径就能描述一个圆弧了。
    但是,半径只需要一个参数,但这里怎么会有两个呢?
    好吧,让你发现了,这里圆角矩形的角实际上不是一个正圆的圆弧,而是椭圆的圆弧,这里的两个参数实际上是椭圆的两个半径,他们看起来个如下图:

    红线标注的 rx 与 ry 就是两个半径,也就是相比绘制矩形多出来的那两个参数。
    我们了解到原理后,就可以为所欲为了,通过计算可知我们上次绘制的矩形宽度为700,高度为300,当你让 rx大于350(宽度的一半), ry大于150(高度的一半) 时奇迹就出现了, 你会发现圆角矩形变成了一个椭圆, 他们画出来是这样的 ( 为了方便确认我更改了画笔颜色, 同时绘制出了矩形和圆角矩形 ):
        // 矩形
        RectF rectF = new RectF(100,100,800,400);  
    
        // 绘制背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);
    
        // 绘制圆角矩形
        mPaint.setColor(Color.BLUE);
        canvas.drawRoundRect(rectF,700,400,mPaint);
    


    其中灰色部分是我们所选定的矩形,而里面的圆角矩形则变成了一个椭圆,实际上在rx为宽度的一半,ry为高度的一半时,刚好是一个椭圆,通过上面我们分析的原理推算一下就能得到,而当rx大于宽度的一半,ry大于高度的一半时,实际上是无法计算出圆弧的,所以drawRoundRect对大于该数值的参数进行了限制(修正),凡是大于一半的参数均按照一半来处理。
    绘制椭圆:
    相对于绘制圆角矩形,绘制椭圆就简单的多了,因为他只需要一个矩形矩形作为参数:
        // 第一种
        RectF rectF = new RectF(100,100,800,400);
        canvas.drawOval(rectF,mPaint);
    
        // 第二种
        canvas.drawOval(100,100,800,400,mPaint);
    

    同样,以上两种方法效果完全一样,但一般使用第一种。


    绘制椭圆实际上就是绘制一个矩形的内切图形,原理如下,就不多说了:

    PS: 如果你传递进来的是一个长宽相等的矩形(即正方形),那么绘制出来的实际上就是一个圆。
    绘制圆:
    绘制圆形也比较简单, 如下:
    canvas.drawCircle(500,500,400,mPaint);  // 绘制一个圆心坐标在(500,500),半径为400 的圆。
    

    绘制圆形有四个参数,前两个是圆心坐标,第三个是半径,最后一个是画笔。


    绘制圆弧:
    绘制圆弧就比较神奇一点了,为了理解这个比较神奇的东西,我们先看一下它需要的几个参数:

    // 第一种
    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) {}

    从上面可以看出,相比于绘制椭圆,绘制圆弧还多了三个参数:

    startAngle  // 开始角度
    sweepAngle  // 扫过角度
    useCenter   // 是否使用中心
    

    通过字面意思我们基本能猜测出来前两个参数(startAngle, sweepAngel)的作用,就是确定角度的起始位置和扫过角度, 不过第三个参数是干嘛的?试一下就知道了,上代码:

        RectF rectF = new RectF(100,100,800,400);
        // 绘制背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);
    
        // 绘制圆弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF,0,90,false,mPaint);
    
        //-------------------------------------
    
        RectF rectF2 = new RectF(100,600,800,900);
        // 绘制背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF2,mPaint);
    
        // 绘制圆弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF2,0,90,true,mPaint);
    

    上述代码实际上是绘制了一个起始角度为0度,扫过90度的圆弧,两者的区别就是是否使用了中心点,结果如下:


    可以发现使用了中心点之后绘制出来类似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。这样中心点这个参数的作用就很明显了,不必多说想必大家试一下就明白了。 另外可以关于角度可以参考一下这篇文章: 角度与弧度
    相比于使用椭圆,我们还是使用正圆比较多的,使用正圆展示一下效果:
        RectF rectF = new RectF(100,100,800,400);
        // 绘制背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF,mPaint);
    
        // 绘制圆弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF,0,90,false,mPaint);
    
        //-------------------------------------
    
        RectF rectF2 = new RectF(100,600,800,900);
        // 绘制背景矩形
        mPaint.setColor(Color.GRAY);
        canvas.drawRect(rectF2,mPaint);
    
        // 绘制圆弧
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF2,0,90,true,mPaint);
    


    简要介绍Paint
    看了上面这么多,相信有一部分人会产生一个疑问,如果我想绘制一个圆,只要边不要里面的颜色怎么办?
    很简单,绘制的基本形状由Canvas确定,但绘制出来的颜色,具体效果则由Paint确定
    如果你注意到了的话,在一开始我们设置画笔样式的时候是这样的:
    mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
    为了展示方便,容易看出效果,之前使用的模式一直为填充模式,实际上画笔有三种模式,如下:
    STROKE                //描边
    FILL                  //填充
    FILL_AND_STROKE       //描边加填充
    

    为了区分三者效果我们做如下实验:

        Paint paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStrokeWidth(40);     //为了实验效果明显,特地设置描边宽度非常大
    
        // 描边
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawCircle(200,200,100,paint);
    
        // 填充
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(200,500,100,paint);
    
        // 描边加填充
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawCircle(200, 800, 100, paint);
    


    一图胜千言,通过以上实验我们可以比较明显的看出三种模式的区别,如果只需要边缘不需要填充内容的话只需要设置模式为描边(STROKE)即可。
    其实关于Paint的内容也是有不少的,这些只是冰山一角,在后续内容中会详细的讲解Paint。

    相关文章

      网友评论

          本文标题:Android自定义View进阶:绘制基本形状(一)

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