这个系列主要是介绍下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(单精度浮点型)的

除了精度不同,两种提供的方法也略微存在差别。在这里我们临时无需关注,想了解很多其它參见官方文档 RectRectF


绘制圆角矩形:

相同有两个重载方法

一般我们使用第一个

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绘制基本图形的更多相关文章

  1. Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解

    Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...

  2. ANDROID Porting系列二、配置一个新产品

    ANDROID Porting系列二.配置一个新产品 详细说明 下面的步骤描述了如何配置新的移动设备和产品的makefile运行android. 1.         目录//vendor/创建一个公 ...

  3. Android自定义控件系列(二)—icon+文字的多种效果实现

    转载请注明出处:http://www.cnblogs.com/landptf/p/6290810.html 今天给大家带来一个很简单但是很常用的控件ButtonExtendM,在开发中我们经常会用到图 ...

  4. 自定义View—绘制基本图形

    一.Canvas能够绘制哪些图形 二.

  5. Android之不须要自己定义View(ViewfindView.java)最简单的二维码扫描

    不废话,先爆照 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/d ...

  6. Android学习系列(二)布局管理器之线性布局的3种实现方式

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39643669 LinearLayout是Android控件中的线性布局控件,它包括的子控件 ...

  7. Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  8. Path类的最全面具体解释 - 自己定义View应用系列

    前言 自己定义View是Android开发人员必须了解的基础:而Path类的使用在自己定义View绘制中发挥着很关键的数据 网上有大量关于自己定义View中Path类的文章.但存在一些问题:内容不全. ...

  9. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

随机推荐

  1. python读取doc

    import os, time, fnmatch from docx import Document class search: def __init__(self, path, search_str ...

  2. 记录一次lnmp故障报告

    业务架构图: nginx 状态监控图: 本次故障的表现为:前端php页面无法打开,空白页或者502错误. nginx中php配置如下: location ~ \.php$ { root /xxx/xx ...

  3. 【C++】指针和new相关

    看黄邦勇帅的笔记. 指针和new之前觉得已经掌握的很好了,可是看了资料还是get到了新知识.记录一下. 1.指针只支持 4 种算术运算符:++,――,+,-.指针只能与整数加减.指针运算的原则是:每当 ...

  4. KVM(三)I/O 全虚拟化和准虚拟化

    在 QEMU/KVM 中,客户机可以使用的设备大致可分为三类: 1. 模拟设备:完全由 QEMU 纯软件模拟的设备. 2. Virtio 设备:实现 VIRTIO API 的半虚拟化设备. 3. PC ...

  5. LUA脚本中O(2)级素数查询

    --================================================================================================== ...

  6. PHP常用函数及其注释

    <?php //===============================时间日期=============================== //y返回年最后两位,Y年四位数,m月份数字 ...

  7. spark技术热点问题互动问答2

    决胜云计算大数据时代” Spark亚太研究院100期公益大讲堂 [第3期互动问答分享] Q1: groupbykey是排好序的吗?分组排序怎么实现? groupByKey在一个由(K,V)对组成的数据 ...

  8. 【cocos2d-js官方文档】十一、cc.path

    概述 该单例是为了方便开发者操作文件路径所设计的.定义为cc.path的目的是为了跟nodejs的path保持一致.里面定义的api也基本跟nodejs的path模块一致,但不全有,今后可能还会继续根 ...

  9. 计蒜客 30990.An Olympian Math Problem-数学公式题 (ACM-ICPC 2018 南京赛区网络预赛 A)

    A. An Olympian Math Problem 54.28% 1000ms 65536K   Alice, a student of grade 66, is thinking about a ...

  10. dart Stream