6.4 Android绘图技巧(Primary:四大方法&Layer)

1.Canvas的四大金刚

  • Canvas.save() 这个方法从字面上可以理解为保存画布,作用就是将之前的所有已绘制的图像保存起来。让后续的操作就好像在一个新的图层上操作一样,这一点与Photoshop中的图层理解基本一致。
  • Canvas.restore() 可以理解为Photoshop中的合并图层操作,作用是将我们在save()之后绘制的所有图像与save()之前的图像进行合并。
  • Canvas.translate() Android默认绘图坐标零点位于屏幕左上角,那么在调用translate()之后,则将零点(0,0)移动到了(x,y)。之后所有绘图操作都将以(x,y)为原点执行。
  • Canvas.rotate() 与translate()同理,旋转坐标系一个一定的角度。

2.Demo:仪表盘

2.1.画外圆

2.2.画刻度和刻度值

2.3.画指针

2.4.全代码和运行结果

Clock.java:

package com.yishengxu.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class Clock extends View {

    private int mHeight, mWidth;

    public Clock(Context context) {
        super(context);
    }

    public Clock(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        // 获取宽高参数
        mWidth = getMeasuredWidth();
        mHeight = getMeasuredHeight();
        // 画外圆
        Paint paintCircle = new Paint();
        paintCircle.setStyle(Paint.Style.STROKE);
        paintCircle.setAntiAlias(true);
        paintCircle.setStrokeWidth(5);
        canvas.drawCircle(mWidth / 2,
                mHeight / 2, mWidth / 2, paintCircle);
        // 画刻度
        Paint painDegree = new Paint();
        paintCircle.setStrokeWidth(3);
        for (int i = 0; i < 24; i++) {
            // 区分整点与非整点
            if (i == 0 || i == 6 || i == 12 || i == 18) {
                painDegree.setStrokeWidth(5);
                painDegree.setTextSize(30);
                canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,//基线起点x
                        mWidth / 2, mHeight / 2 - mWidth / 2 + 60,//基线起点y
                        painDegree);
                String degree = String.valueOf(i);//Integer.toString(i)
                canvas.drawText(degree,
                        mWidth / 2 - painDegree.measureText(degree) / 2,//measureText()在画布上输出文本之前,检查字体的宽度:
                        mHeight / 2 - mWidth / 2 + 90,
                        painDegree);
            } else {
                painDegree.setStrokeWidth(3);
                painDegree.setTextSize(15);
                canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
                        mWidth / 2, mHeight / 2 - mWidth / 2 + 30,
                        painDegree);
                String degree = String.valueOf(i);
                canvas.drawText(degree,
                        mWidth / 2 - painDegree.measureText(degree) / 2,
                        mHeight / 2 - mWidth / 2 + 60,
                        painDegree);
            }
            // 通过旋转画布简化坐标运算
            canvas.rotate(15, mWidth / 2, mHeight / 2);//二三参数为枢轴点的xy,枢轴点即旋转中心
        }
        // 画圆心
        Paint paintPointer = new Paint();
        paintPointer.setStrokeWidth(30);
        canvas.drawPoint(mWidth / 2, mHeight / 2, paintPointer);
        // 画指针
        Paint paintHour = new Paint();
        paintHour.setStrokeWidth(20);
        Paint paintMinute = new Paint();
        paintMinute.setStrokeWidth(10);
        canvas.save();//只是保存“缓冲区”绘制的内容
        canvas.translate(mWidth / 2, mHeight / 2);
        canvas.drawLine(0, 0, 100, 100, paintHour);
        canvas.drawLine(0, 0, 100, 200, paintMinute);
        canvas.restore();//将“缓冲区”绘制的内容和已经save()的内容一同合并并保存起来,这里跟上边的save注意区分开来
    }
}

MainActivity.java:

package com.yishengxu.myapplication;

import android.app.Activity;
import android.os.Bundle;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new Clock(this));
    }
}

效果图:

3.Layer图层

创建一个新的Layer到“栈”中,可以使用saveLayer(), savaLayerAlpha(), 从“栈”中推出一个Layer,可以使用restore(),restoreToCount()。但Layer入栈时,后续的DrawXXX操作都发生在这个Layer上,而Layer退栈时,就会把本层绘制的图像“绘制”到上层或是Canvas上,在复制Layer到Canvas上时,可以指定Layer的透明度

  • 透明度:
  • 127,半透明
  • 255,完全不透明
  • 0,完全透明 实例如Demo下图:

上Demo:

package com.imooc.myapplication;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyLayer(this));
    }

    public class MyLayer extends View {

        private Paint mPaint;
        private static final int LAYER_FLAGS =
                        Canvas.MATRIX_SAVE_FLAG |
                        Canvas.CLIP_SAVE_FLAG |
                        Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
                        Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                        Canvas.CLIP_TO_LAYER_SAVE_FLAG;//此乃API定义的常量,ctrl+E 进入文档查看便知晓其含义

        public MyLayer(Context context) {
            super(context);
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);//背景
            mPaint.setColor(Color.BLUE);
            canvas.drawCircle(150, 150, 100, mPaint);//“零图层”

            canvas.saveLayerAlpha(0, 0, 400, 400, 127, LAYER_FLAGS);
            mPaint.setColor(Color.RED);
            canvas.drawCircle(200, 200, 100, mPaint);
            canvas.restore();
        }
    }
}

半透明:

完全不透明: canvas.saveLayerAlpha(0, 0, 400, 400, 255, LAYER_FLAGS);

image.png

完全透明: canvas.saveLayerAlpha(0, 0, 400, 400, 0, LAYER_FLAGS);

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏移动开发

android 圆角图片的实现和封装

下面为主要源码,实现了 Picasso 中的 Transformation 接口。

32340
来自专栏androidBlog

Android 圆形头像的两种实现方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/de...

25800
来自专栏向治洪

PullToRefreshScrollView 嵌套RecyclerView实现特卖列表倒计时抢购

不久之前,我们谈到了通过Handler与timer及TimerTask结合实现倒计时抢购列表,那个是PullToRefreshListView实现的,今天要讲的...

36650
来自专栏郭霖

Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效

之前我向大家介绍了史上最简单的滑动菜单的实现方式,相信大家都还记得。如果忘记了其中的实现原理或者还没看过的朋友,请先去看一遍之前的文章 Android滑动菜单特...

35460
来自专栏androidBlog

Android打造不一样的新手引导页面(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

9210
来自专栏向治洪

墨迹天气3.0引导动画

 实现墨迹天气向上滑动的viewpager使用的开源库ViewPager-Android。ViewPager-Android开源库设置app:orientati...

28870
来自专栏Jack的Android之旅

教你实现最简单的QQ消息item侧滑菜单

这次跟大家介绍怎么简单的实现类似QQ消息Item的左右滑动菜单的实现。首先见效果图先:

14920
来自专栏Android小菜鸡

Touch事件实现View拖动

  Touch监听事件可以监听手指在屏幕上的行为,例如按下、滑动。抬起。根据这些事件,可以做出View任意推动的效果。

21210
来自专栏Felix的技术分享

Android快速索引条控件QuickIndexBar

28670
来自专栏Android干货园

Android 自定义上面圆角下面直角的ImageView

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/48...

96040

扫码关注云+社区

领取腾讯云代金券