Android画图系列(二)——自己定义View绘制基本图形
这个系列主要是介绍下Android自己定义View和Android画图机制。自己能力有限。假设在介绍过程中有什么错误。欢迎指正
前言
在上一篇Android画图系列(一)——自己定义View基础中我们了解自己定义View相关的基本知识。只是,这些东西依然还是理论,接下来我们就实际绘制一些东西
在本篇文章中,我们先了解下面Canvas,而且画一些主要的图形
Canvas简单介绍
Canvas我们能够称之为画布。能够在上面绘制各种东西。是安卓平台2D图形绘制的基础。非常强大。
一般来说,比較基础的东西有两大特点:
1.可操作性强:因为这些是构成上层的基础,所以可操作性必定十分强大。
2.比較难用:各种方法太过基础,想要完美的将这些操作组合起来有一定难度。**
Canvas的经常使用操作
操作类型 | 相关API | 备注 |
---|---|---|
绘制颜色 | drawColor, drawRGB, drawARGB | 使用单一颜色填充整个画布 |
绘制基本形状 | drawPoint, drawPoints, drawLine, drawLines, drawRect, drawRoundRect, drawOval, drawCircle, drawArc | 依次为 点、线、矩形、圆角矩形、椭圆、圆、圆弧 |
绘制图片 | drawBitmap, drawPicture | 绘制位图和图片 |
绘制文本 | drawText, drawPosText, drawTextOnPath | 依次为 绘制文字、绘制文字时指定每一个文字位置、依据路径绘制文字 |
绘制路径 | drawPath | 绘制路径。绘制贝塞尔曲线时也须要用到该函数 |
顶点操作 | drawVertices, drawBitmapMesh | 通过对顶点操作能够使图像形变,drawVertices直接对画布作用、 drawBitmapMesh仅仅对绘制的Bitmap作用 |
画布剪裁 | clipPath, clipRect | 设置画布的显示区域 |
画布快照 | save, restore, saveLayerXxx, restoreToCount, getSaveCount | 依次为 保存当前状态、 回滚到上一次保存的状态、 保存图层状态、 回滚到指定状态、 获取保存次数 |
画布变换 | translate, scale, rotate, skew | 依次为 位移、缩放、 旋转、错切 |
Matrix(矩阵) | getMatrix, setMatrix, concat | 实际画布的位移。缩放等操作的都是图像矩阵Matrix,仅仅只是Matrix比較难以理解和使用。故封装了一些经常使用的方法。 |
PS: Canvas经常用法在上面表格中已经所有列出了。当然还存在一些其它的方法未列出,详细能够參考官方文档 Canvas
绘制基本图形
绘制颜色:
绘制颜色是填充整个画布。经常使用于绘制底色。
canvas.drawColor(Color.RED);
首先我们写一个类继承View,而且我们onDraw()方法中调用这种方法
package com.study.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by HFS on 2017/2/4.
*/
public class CustomView extends View {
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.RED);
}
}
OK。看下效果
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR3JlYXRoZnM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
注意:接下来绘制的图形都须要另外一个參数:Paint 能够把Canvas理解为画布。Paint理解为画笔
- 初始化画笔
// 1.创建一个画笔
private Paint mPaint = new Paint();
// 2.初始化画笔
private void initPaint() {
mPaint.setColor(Color.BLACK); //设置画笔颜色
mPaint.setStyle(Paint.Style.FILL); //设置画笔模式为填充
mPaint.setStrokeWidth(10f); //设置画笔宽度为10px
}
// 3.在构造函数中初始化
public xxxView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
在创建完画笔之后。就能够在Canvas中绘制各种内容了。
绘制点
直接上代码了
package com.study.customview.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by HFS on 2017/2/4.
*/
public class PointView extends View {
private Paint mPaint=new Paint();
public PointView(Context context) {
super(context);
initPaint();
}
public PointView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public PointView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画一个点
canvas.drawPoint(200,300,mPaint);
//画一组点
canvas.drawPoints(new float[]{
500,600,
500,700,
500,800,
500,900
},mPaint);
}
}
效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR3JlYXRoZnM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
注意:坐标点都是相对于屏幕左上角而言的。坐标原点默认在左上角。水平向右为x轴增慷慨向,竖直向下为y轴增慷慨向。
绘制直线
直接上代码:
package com.study.customview.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by HFS on 2017/2/4.
* 直线View
*/
public class LineView extends View {
private Paint mPaint=new Paint();
public LineView(Context context) {
super(context);
initPaint();
}
public LineView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public LineView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//从(200,300)这个点開始 到(500,600)这个点结束
canvas.drawLine(200,400,500,600,mPaint);
// 绘制一组线 每四数字(两个点的坐标)确定一条线
canvas.drawLines(new float[]{
100,200,200,200,
100,300,200,300
},mPaint);
}
}
效果图:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR3JlYXRoZnM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
绘制矩形
关于绘制矩形,Canvas提供了三种重载方法
解释下:
第一种就是提供四个数值(矩形左上角和右下角两个点的坐标)来确定一个矩形进行绘制。
其余两种是先将矩形封装为Rect或RectF(实际上仍然是用两个坐标点来确定的矩形),然后传递给Canvas绘制
package com.study.customview.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by HFS on 2017/2/4.
*/
public class RectView extends View {
private Paint mPaint=new Paint();
public RectView(Context context) {
super(context);
initPaint();
}
public RectView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public RectView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//第一种
canvas.drawRect(200,300,500,600,mPaint);
//另外一种
Rect rect=new Rect(200,300,500,600);
canvas.drawRect(rect,mPaint);
//第三种
RectF rectF=new RectF(200,300,500,600);
canvas.drawRect(rectF,mPaint);
}
}
效果图
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR3JlYXRoZnM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
为什么会有Rect和RectF两种?两者有什么差别吗?
答案当然是存在差别的,两者最大的差别就是精度不同。Rect是int(整形)的,而RectF是float(单精度浮点型)的。
除了精度不同,两种提供的方法也略微存在差别。在这里我们临时无需关注,想了解很多其它參见官方文档 Rect 和 RectF
绘制圆角矩形:
相同有两个重载方法
一般我们使用第一个
package com.study.customview.widget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by HFS on 2017/2/4.
* 圆角矩形View
*/
public class RoundRectView extends View {
private Paint mPaint=new Paint();
public RoundRectView(Context context) {
super(context);
initPaint();
}
public RoundRectView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public RoundRectView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
/**
* 初始化画笔
*/
private void initPaint() {
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStrokeWidth(10f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF rect=new RectF(100,100,800,400);
canvas.drawRoundRect(rect,30,30,mPaint);
}
}
效果图
注意:下面截取自http://www.gcssloop.com/customview/Canvas_BasicGraphics
下面简单解析一下圆角矩形的几个必要的參数的意思。
非常明显能够看出,另外一种方法前四个參数和第一种方法的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对大于该数值的參数进行了限制(修正)。凡是大于一半的參数均依照一半来处理。
绘制椭圆:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//第一种
RectF rectF=new RectF(100,100,800,400);
canvas.drawOval(rectF,mPaint);
//另外一种
canvas.drawOval(100,100,800,400,mPaint);
}
}
相同。以上两种方法效果全然一样,但一般使用第一种。
绘制椭圆实际上就是绘制一个矩形的内切图形,原理例如以下,就不多说了:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvR3JlYXRoZnM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">
PS: 假设你传递进来的是一个长宽相等的矩形(即正方形),那么绘制出来的实际上就是一个圆。
绘制圆:
绘制圆形也比較简单, 例如以下:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//在(600,600)这个点绘制一个半径为300的圆
canvas.drawCircle(600,600,300,mPaint);
}
绘制圆形有四个參数。前两个是圆心坐标,第三个是半径,最后一个是画笔。
绘制圆弧:
绘制圆弧就比較奇妙一点了。为了理解这个比較奇妙的东西。我们先看一下它须要的几个參数:
// 第一种
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度的圆弧,两者的差别就是是否使用了中心点。结果例如以下:
能够发现使用了中心点之后绘制出来相似于一个扇形,而不使用中心点则是圆弧起始点和结束点之间的连线加上圆弧围成的图形。这样中心点这个參数的作用就非常明显了,不必多说想必大家试一下就明确了
Ok,这篇就这些吧
Github地址
Android画图系列(二)——自己定义View绘制基本图形的更多相关文章
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- ANDROID Porting系列二、配置一个新产品
ANDROID Porting系列二.配置一个新产品 详细说明 下面的步骤描述了如何配置新的移动设备和产品的makefile运行android. 1. 目录//vendor/创建一个公 ...
- Android自定义控件系列(二)—icon+文字的多种效果实现
转载请注明出处:http://www.cnblogs.com/landptf/p/6290810.html 今天给大家带来一个很简单但是很常用的控件ButtonExtendM,在开发中我们经常会用到图 ...
- 自定义View—绘制基本图形
一.Canvas能够绘制哪些图形 二.
- Android之不须要自己定义View(ViewfindView.java)最简单的二维码扫描
不废话,先爆照 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...
- Android学习系列(二)布局管理器之线性布局的3种实现方式
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39643669 LinearLayout是Android控件中的线性布局控件,它包括的子控件 ...
- Android应用层View绘制流程与源码分析
1 背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...
- Path类的最全面具体解释 - 自己定义View应用系列
前言 自己定义View是Android开发人员必须了解的基础:而Path类的使用在自己定义View绘制中发挥着很关键的数据 网上有大量关于自己定义View中Path类的文章.但存在一些问题:内容不全. ...
- 【朝花夕拾】Android自定义View篇之(一)View绘制流程
前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...
随机推荐
- POJ2680(动态规划,大数)
Computer Transformation Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4548 Accepted ...
- kthread_create与kernel_thread的区别【栈】
转自:http://blog.chinaunix.net/uid-25513153-id-2888903.html kthread_create与kernel_thread的区别 kernel thr ...
- Linux设备模型(3)_Uevent【转】
转自:http://www.wowotech.net/device_model/uevent.html 1. Uevent的功能 Uevent是Kobject的一部分,用于在Kobject状态发生改变 ...
- spring 声明式事务中try catch捕获异常
原文:http://heroliuxun.iteye.com/blog/848122 今天遇到了一个这个问题 最近遇到这样的问题,使用spring时,在业务层需要捕获异常(特殊需要),当前一般情况下不 ...
- xshell命令大全
suse linux 常用命令 (1)命令ls——列出文件 ls -la 给出当前目录下所有文件的一个长列表,包括以句点开头的“隐藏”文件 ls a* 列出当前目录下以字母a开头的所有文件 ls -l ...
- 使用echarts展示线状图信息的时候数据部分数据因为x轴的数据显示不全而隐藏的问题
在使用echarts来展示数据时,因为数据很多的原因导致x轴显示不全,然后有些数据也隐藏在图表中,所以这个时候我们要在 series 中设置一个属性,让所有的数据都能够展示出来,这里我们需要添加的属性 ...
- [设计模式-行为型]访问者模式(Vistor)
一句话 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作. 概括
- SyntaxError: Non-ASCII character '\xe7' in file 错误的解决方法
在代码开头写下面的定义即可 #encoding:utf-8
- centos6.5 的rpm 可以来这边找
http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepo-el6/epel-6-i386/gcc-4.8.2-16.3.fc20/
- 第3天-DIV+CSS布局
盒子模型 margin 设置外边距宽度 有4个值的时候: maigin 10px 5px 15px 20px; (上.右.下.左)有3个值的时候: margin: 10px 5px 15px; (上. ...