使用Canvas类绘制基本图形、渐变及阴影

2016-05-25 / 5 阅读 / Android

Canvas类提供丰富的绘图方法,想要绘出一个漂亮的控件,这些方法坑定是要熟练使用的。最近花了一点时间来熟悉一下这些常用的方法。在这边一一记下,哪怕一时忘记,也可以过来看看立马回忆起来。


这边我通过继承View,并重写onDraw方法来练习
为了解释方便,参数1,参数2分别用P1和P2来表示后面参数以此类推

绘制网格

为了能更宏观的观察坐标系,給画上网格和坐标
@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int width = getWidth();
        int height = getHeight();


        //绘制基准网格
        int interval = 100;
        {
            Paint paint = new Paint();
            paint.setStrokeWidth(2);
            paint.setColor(Color.RED);

            //横线
            for (int i=0; i < height; i=i+interval) {
                canvas.drawLine(0, i, width, i,paint);
            }
            //竖线
            for (int j=0; j < width; j=j+interval) {
                canvas.drawLine(j, 0, j, height,paint);
            }
            //坐标
            paint.setTextSize(25);
            paint.setTypeface(Typeface.MONOSPACE);

            Paint point = new Paint();
            point.setColor(Color.YELLOW);
            point.setStrokeWidth(3);
            for (int x=0; x < width; x=x+2*interval){
                for (int y=0; y < height; y=y+2*interval) {
                    canvas.drawText("("+x+","+y+")",x,y+25,paint);
                    canvas.drawPoint(x, y, point);
                }
            }
        }

绘制直线

绘制直线有三个方法
  1. 绘制单条直线,给定端点绘制

  2. 绘制多条直线,给定一定数量的float,分别4个数表示一个条单个直线,所以数组长度要是4的倍数

  3. 是对方法2的一个扩展,有时候给定数组我们并想全部绘出,只想绘出部分直线,这边便可以通过接下来的2个参数来控制,跳过的多少长度,到某个长度以内的直线。

        //绘制直线
        {
            Paint paint = new Paint();
            paint.setStrokeWidth(2);
            paint.setColor(Color.GREEN);

            canvas.drawLine(0, 0, 200, 200, paint);//方法1
            canvas.drawLines(new float[]{200, 200, 400, 0}, paint);//方法2
            canvas.drawLines(new float[]{400, 0, 600, 200, 600, 200, 800, 0}, 0, 8, paint);//方法3

        }

绘制圆

这个很好理解,参数P1和P2分别是圆心x和y坐标,P3是半径
圆形包括一下一些对象都是形状,所以在绘出时会有2中样子,实心和空心(或是填充或是描边)
        //绘制圆
        {
            //绘制实心圆
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);
            canvas.drawCircle(100, 300, 100, paint);

            //绘制空心圆
            paint.setStrokeWidth(2);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(300, 300, 100, paint);
        }

绘制弧线

RectF表示一个抽象的矩形对象,基本构造就是(left,top,right,bottom)弧线就会在这个矩形框内绘出,且与4个边相切。
P2是起始角度,P3是结束角度
弧线说穿了算是一个残缺的椭圆,所以有圆心,所有Android为我们提供了P4(当true时连到两个端点会连接中心,false时端点会直接相连)
        //绘制弧线
        {
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);

            //绘制到中心的实心弧
            canvas.drawArc(new RectF(400, 200, 600, 400), 90, 130, true, paint);

            //绘制不到中心的实心弧
            canvas.drawArc(new RectF(600, 200, 800, 400), 90, 130, false, paint);

            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(2);

            //绘制到中心的空心弧
            canvas.drawArc(new RectF(800, 200, 1000, 400), 90, 130, true, paint);

            //绘制不到中心的空心弧
            canvas.drawArc(new RectF(800, 0, 1000, 200), 90, 130, false, paint);
        }

绘制矩形

非常简单只要,只要指定(left,top,right,bottom)

        //矩形
        {
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);

            //实心矩形
            canvas.drawRect(0, 400, 200, 600, paint);

            //空心矩形
            paint.setStrokeWidth(2);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawRect(200, 400, 400, 600, paint);
        }

绘制圆角矩形

与矩形绘制类似除了要指定RectF参数外,还需要指定圆角的大小P2(x轴方向圆角半径),P3(y轴方向圆角半径)
        //圆角矩形
        {
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);

            //实心圆角矩形
            canvas.drawRoundRect(new RectF(400, 400, 600, 600), 40, 40, paint);

            //空心圆角矩形
            paint.setStrokeWidth(2);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawRoundRect(new RectF(600, 400, 800, 600), 40, 40, paint);
        }

绘制椭圆

绘制椭圆与绘制圆弧很像,都需要指定一个矩形区域,系统会自动在该区域绘制椭圆

````java
//椭圆
{
Paint paint = new Paint();
paint.setColor(Color.GREEN);

        //实心椭圆
        canvas.drawOval(new RectF(0, 600, 400, 800), paint);

        //空心椭圆
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawOval(new RectF(400, 600, 800, 800), paint);
    }

#### 绘制路径
>强大的路径,几乎拥有它其他皆可以抛弃

这边可以能需要介绍下Path类及一些操作方法
- public void moveTo(float x, float y)
移动到某个绝对坐标,它不会留下任何绘图痕迹,只是移动这一抽象动作
- public void rMoveTo(float dx, float dy)
与上一个方法类似也是用于移动,不过它移动的距离是相对当前坐标(Path类中提供很多 r***( ... ) 都是相对坐标,所以以下不再一一列出)
- public void lineTo(float x, float y)
从当前点到x和y画一条直线
- public void addArc(RectF oval, float startAngle, float sweepAngle)
画一个圆弧
- public void arcTo(RectF oval, float startAngle, float sweepAngle)
画一个圆弧,并且起点与当前点相连

这边就先介绍到这里,还有其他一些强大的功能暂时没时间看

```java
        //路径
        {
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);
            paint.setStrokeWidth(2);

            //实心不规则形状
            Path path = new Path();
            path.moveTo(0, 800);
            path.rLineTo(100, 50);
            path.rLineTo(100, -50);
            path.rLineTo(-50, 100);
            path.rLineTo(50, 100);
            path.rLineTo(-100, -50);
            path.rLineTo(-100, 50);
            path.rLineTo(50, -100);
            path.close();
            canvas.drawPath(path, paint);


            //实心不规则形状
            paint.setStyle(Paint.Style.STROKE);
            path.reset();
            path.moveTo(200, 800);
            path.rLineTo(100, 50);
            path.rLineTo(100, -50);
            path.rLineTo(-50, 100);
            path.rLineTo(50, 100);
            path.rLineTo(-100, -50);
            path.rLineTo(-100, 50);
            path.rLineTo(50, -100);
            path.close();
            canvas.drawPath(path, paint);

            //带弧线形状
            path.reset();
            path.moveTo(400, 800);
            path.lineTo(500, 800);
            path.arcTo(new RectF(400, 800, 600, 1000), 0, 45, false);

            path.arcTo(new RectF(400, 800, 600, 1000), 90, 120, true);
            canvas.drawPath(path, paint);
        }

绘制渐变效果

这里的渐变大致可以分3种
  1. 线性渐变 - 直线渐变

  2. 圆形渐变-由内圈到外圈的渐变

  3. 角度渐变 - 360度的渐变效果
    P1~P4为渐变的直线方向,P5为颜色数组,P6为颜色在渐变种所处位置

 


        //渐变
        {
            Paint paint = new Paint();

            //线性渐变
            LinearGradient linearGradient = new LinearGradient(0,0,100,0,new int[]{Color.argb(255,50,50,50),Color.argb(255,200,200,200),Color.argb(255,50,50,50)},new float[]{0,0.5f,1}, Shader.TileMode.MIRROR);
            paint.setShader(linearGradient);
            paint.setTextSize(30);
            canvas.drawText("线性渐变",0,1100,paint);

            //圆形渐变
            RadialGradient radialGradient = new RadialGradient(300, 1100, 100, Color.GREEN, Color.TRANSPARENT, Shader.TileMode.MIRROR);
            paint.setShader(radialGradient);
            paint.setTextSize(30);
            canvas.drawCircle(300, 1100,100, paint);

            //角度渐变
            SweepGradient sweepGradient = new SweepGradient(500,1100,Color.GREEN,Color.TRANSPARENT);
            paint.setShader(sweepGradient);
            canvas.drawArc(new RectF(400, 1000, 600, 1200), 0, 360, true, paint);
        }

绘制阴影

设置阴影是通过设置Paint的ShadowLayer参数P1为扩散半径,P2,P3分别为x和y轴偏移位置
有个注意点,就是当没有效果时可能需要通过setLayerType(LAYER_TYPE_SOFTWARE, null);来关闭硬件加速
因为有些绘制效果在硬件加速下无法正常显示。

        //绘制阴影
        {
            Paint paint = new Paint();
            paint.setColor(Color.GREEN);
            paint.setTextSize(30);
            paint.setShadowLayer(5, 10, 10, Color.RED);
            setLayerType(LAYER_TYPE_SOFTWARE, null);//关闭硬件加速
            canvas.drawText("有阴影的字", 650, 1100, paint);
        }
    }

整个以上例子的效果如下图

相关推荐