自定义View ——Canvas之绘制基本形状

自定义View ——Canvas之绘制基本形状##

转载出处:http://www.gcssloop.com/customview/Canvas_Convert/

一.Canvas简介###

Canvas 称之为画布,是安卓平台2D图形绘制的基础,非常强大。

一般来说,比较基础的东西有两大特点:

1.可操作性强:由于这些是构成上层的基础,所以可操作性必然十分强大。

2.比较难用:各种方法太过基础,想要完美的将这些操作组合起来有一定难度。

本系列文章不仅会介绍到Canvas的操作方法,还会简单介绍一些设计思路和技巧。

二.Canvas的常用操作速查表##

列表:

操作类型 相关API 备注
绘制颜色 drawColor,drawRGB,drawARGB 使用单一颜色填充整个画布
绘制基本形状 drawPoint,drawPoints,drawLine,drawLines,drawRect,drawRountRect,drawOval,drawCircle,drawArc 依次为点、线、矩形、圆角矩形、椭圆、圆、圆弧
绘制图片 drawBitmap,drawPicture 绘制位图和图片
绘制文本 drawText,drawPosText,drawTextOnPath 依次为 绘制文字、绘制文字时指定每个文字位置、根据路径绘制文字
顶点操作 drawVertices,drawBitmapMesh 通过对顶点操作可以使图像形变,drawVertices直接对画布作用、drawBitmapMesh只对绘制的Bitmap作用
绘制路径 drawPath 绘制路径,绘制贝塞尔曲线时也需要用该函数
画布剪裁 clipPath,clipRect 设置画布的显示区域
画布快照 save,restore,saveLayerXxx,restoreToCount,getSaveCount 依次为保存当前状态、回滚到上一次保存的状态、保存图层状态、回滚到指定状态、获取保存次数
画布变换 translate,scale,rotate,skew 依次为位移、缩放、旋转、错切
Matrix矩阵 getMatrix、setMatrix、concat 实际画布的位移,缩放等操作的都是图像矩阵Matrix,只不过Matrix比较难以理解和使用,故封装了一些常用的方法。

三、Canvas详解###

本篇内容主要讲解如何利用Canvas绘制基本图形。

绘制颜色:

绘制颜色是填充整个画布,常用于绘制底色。

代码:

canvas.drawColor(Color.BLUE);//绘制蓝色

如图:

创建画笔:

想绘制内容,首先需要先创建一个画笔,如下:
//创建一个画笔
private Paint mPaint=new Paint();
//初始化画笔
private void initPaint(){
mPaint.setColor(Color.BLACK); //设置画笔颜色
mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
mPaint.setStrokeWidth(10f); //设置画笔宽度为10px
}
//在构造函数中初始化
public SloopView(Context context,AttributeSet attrs){
super(context,attrs);
initPaint();
}

在创建完画笔之后,就可以在Canvas中绘制各种内容了。


绘制点:###

可以绘制一个点,也可以绘制一组点,如下:

canvas.drawPoint(200,200,mPaint);
canvas.drawPoints(new float[]{
    500,500,
    500,600,
    500,700
},mPaint);

关于坐标原点默认在左上角,水平向右为x轴增大方向,竖直向下为y轴增大方向。

绘制直线:###

绘制直线只需要两个点,初始点和结束点,同样绘制直线也可以绘制一条或者绘制一组:

canvas.drawLine(300,300,500,500,mPaint);//在坐标(300,300)(500,600)之间绘制一条直线
canvas.drawLines(new float[]{            //绘制一组线  每四位数字(两个点的坐标)确定一条线
100,200,200,200,
100,300,200,200
},mpaint);

绘制矩形:###

确定确定一个矩形最少需要四个数据,就是对角线的两个点的坐标值,这里一般采用左上角和右下角的两个点的坐标。

关于绘制矩形,Canvas提供了三种重载方法,第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。其余两种是先将矩形封装为Rect或者RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制,如下:
//第一种
canvas.drawRect(100,100,800,400,mPaint);
//第二种
Rect mRect=new Rect(100,100,800,400);
canvas.drawRect(mRect,mPaint);
//第三种
RectF mRectF=new RectF(100,100,800,400);
canvas.drawRect(mRectF,mPaint);

三种绘制的结果是完全一样的。


绘制圆角矩形###

绘制圆角矩形也提供了两种重载方式,如下:
//第一种
RectF mRectF=new RectF(100,100,800,400);
canvas.drawRoundRect(mRectF,30,30,mPaint);
//第二种
canvas.drawRoundRect(100,100,800,400,30,30,mPaint);

第二种方法在API21的时候才添加上,所以我们一般使用的都是第一种。


与矩形相比,圆角矩形多出来了两个参数rx和ry,这里圆角矩形的角实际上不是一个正圆的圆弧,而是椭圆的圆弧,这里的两个参数实际上是椭圆的两个半径,他们看起来如下图:


红线标注的rx与ry就是两个半径,也就是相比绘制矩形多出来的那两个参数。

我们了解到原理后,就可以为所欲为了,通过计算可知我们上次绘制的矩形宽度为700,高度为300,当你让rx大于350(宽度的一半),ry大于150(高度的一半)时奇迹就出现了,你会发现圆角矩形变成了一个椭圆,他们画出来是这样的(为了方便确认我更改了画笔颜色,同时绘制出了矩形和圆角矩形):

//矩形
RectF  mRectF=new RectF(100,100,800,400);
//绘制背景矩形
mPaint.setColor(Color.GRAY);
canvas.drawRect(mRectF,mPaint);
//绘制圆角矩形
mPaint.setColor(Color.BLUE);
canvas.drawRoundRect(mRectF,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);

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


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

绘制圆:###

如下:

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    //是否使用中心

上代码:

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);

如果想系统学习自定义View,推荐看作者GcsSloop系列文章###

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容