码迷,mamicode.com
首页 > 移动开发 > 详细

Android群英传知识点回顾——第六章:Android绘图机制与处理技巧

时间:2018-09-07 14:17:51      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:map   主线程   mes   计算公式   渲染   drawtext   1.3   final   view   


  • 6.1 屏幕的尺寸信息
    • 6.1.1 屏幕参数
    • 6.1.2 系统屏幕密度
    • 6.1.3 独立像素密度dp
    • 6.1.4 单位转换
  • 6.2 2D绘图基础
  • 6.3 Android XML绘图
    • 6.3.1 Bitmap
    • 6.3.2 Shape
    • 6.3.3 Layer
    • 6.3.4 Selector
  • 6.4 Android绘图技巧
    • 6.4.1 Canvas
    • 6.4.2 Layer图层
  • 6.5 Android图像处理之色彩特效处理
    • 6.5.1 色彩矩阵分析
    • 6.5.2 Android颜色矩阵——ColorMatrix
    • 6.5.3 常用图像颜色矩阵处理效果
    • 6.5.4 像素点分析
    • 6.5.5 常用图像像素点处理效果
  • 6.6 Android图像处理之图形特效处理
    • 6.6.1 Android变形矩阵——Matrix
    • 6.6.2 像素块分析
  • 6.7 Android图像处理之画笔特效处理
    • 6.7.1 PorterDuffXfermode
    • 6.7.2 Shader
    • 6.7.3 PathEffect
  • 6.8 View之孪生兄弟——SurfaceView
    • 6.8.1 SurfaceView与View的区别
    • 6.8.2 SurfaceView的使用
    • 6.8.3 SurfaceView实例

由于这一章比较难理解,所以大部分知识点都是摘抄原文的,如果是没学习过线性代数的同学,那就难上加难了,不过克服它,是你进阶高级工程师的必经之路,文章比较长,请耐心观看

无知识点

  • 屏幕大小:屏幕对角线的长度,通常用寸来度量
  • 分辨率:手机屏幕的像素点个数
  • PPI:每英寸像素,又称DPI,由对角线像素点除以屏幕大小获得

技术分享图片

Android系统使用mdpi即密度值为160的屏幕作为标准,在这个屏幕上1px=1dp

ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12

这里加0.5f的巧用目的是:四舍五入

dp==dip

系统提供了TypedValue类帮助我们转换

Paint作为一个重要的元素有以下方法:

  • setAntiAlias():设置画笔的锯齿效果
  • setColor():设置画笔的颜色
  • setARGB():设置画笔的A、R、G、B值
  • setAlpha():设置画笔的Alpha值
  • setTextSize():设置字体的尺寸
  • setStyle():设置画笔的风格(空心或实心)
  • setStrokeWidth():设置空心边框的宽度

设置Paint的Style可以画出空心或者实心的矩形:

  • paint.setStyle(Paint.Style.STROKE):空心效果
  • paint.setStyle(Paint.Style.FILL):实心效果

技术分享图片

系统通过提供的Canvas对象来提供绘图方法:

  • canvas.drawPoint(x, y, paint):绘制点
  • canvas.drawLine(startX, startY ,endX, endY, paint):绘制直线
  • canvas.drawLines(new float[]{startX1, startY1, endX1, endY1,……,startXn, startYn, endXn, endYn}, paint):绘制多条直线
  • canvas.drawRect(left, top, right, bottom, paint):绘制矩形
  • canvas.drawRoundRect(left, top, right, bottom, radiusX, radiusY, paint):绘制圆角矩形
  • canvas.drawCircle(circleX, circleY, radius, paint):绘制圆
  • canvas.drawOval(left, top, right, bottom, paint):绘制椭圆
  • canvas.drawText(text, startX, startY, paint):绘制文本
  • canvas.drawPosText(text, new float[]{X1,Y1,X2,Y2,……Xn,Yn}, paint):在指定位置绘制文本
  • Path path=new Path();
    path.moveTo(50, 50);
    path.lineTo(100, 100);
    path.lineTo(100, 300);
    path.lineTo(300, 50);
    canvas.drawPath(path, paint):绘制路径

技术分享图片

  • paint.setStyle(Paint.Style.STROKE);
    drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint):绘制扇形
  • paint.setStyle(Paint.Style.STROKE);
    drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint):绘制弧形
  • paint.setStyle(Paint.Style.FILL);
    drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint):绘制实心扇形
  • paint.setStyle(Paint.Style.FILL);
    drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint):绘制实心弧形

技术分享图片

无知识点

通过这样在XML中使用Bitmap就可以将图片直接转换成了Bitmap在程序中使用

通过Shape可以在XML中绘制各种形状

下面通过渐变来实现的阴影效果

技术分享图片

通过Layer会产生图片依次叠加的效果

Selector的作用在于帮助开发者实现静态绘图中的事件反馈,通过给不同的事件设置不同的图像,从而在程序中根据用户输入,返回不同的效果

下面这个例子实现了一个具有点击反馈效果的、圆角举证Selector

技术分享图片

无知识点

Canvas提供了以下几种非常有用的方法:

  • Canvas.save():保存画布,将之前所有已绘制图像保存起来,让后续的操作就好像在一个新的图层上操作一样
  • Canvas.restore():在save()之后绘制的所有图像与save()之前的图像进行合并,可以理解为Photoshop中的合并图层操作
  • Canvas.translate():画布平移
  • Canvas.roate():画布翻转

通过一个实例——仪表盘,来理解这几个方法,将仪表盘分为以下几个元素:

  • 仪表盘:外面的大圆盘
  • 刻度线:包含四个长的刻度线和其他短的刻度线
  • 刻度值:包含长刻度线对应的大的刻度值和其他小的刻度值
  • 指针:中间的指针,一粗一细两根指针

仪表盘……见经典代码案例一

一张复杂的画可以由很多个图层叠加起来,形成一个复杂的图像,使用saveLayer()方法来创建一个图层,图层同样是基于栈的结构进行管理的

技术分享图片

Android通过调用saveLayer()方法,saveLayerAlpha()方法将一个图层入栈,使用restore()方法、restoreToCount()方法将一个图层出栈,仿照API Demos里面的一个实例来使用Layer

  • 当透明度为127时,即半透明
  • 当透明度为255时,即完全不透明
  • 当透明度为0时,即完全透明

技术分享图片

Bitmap图片都是由点阵和颜色值组成的,所谓点阵就是一个包含像素的矩阵,每一个元素对应着图片的一个像素。而颜色值——ARGB,分别对应透明度、红、绿、蓝这四个通道分量,它们共同决定了每个像素点显示的颜色

在色彩处理中,我们通常用三个角度描述一张图片:

  • 色调:物体传播的颜色
  • 饱和度:颜色的纯度,从0(灰)-100%(饱和)来进行描述
  • 亮度:颜色的相对明暗程度

而在Android中,系统会使用一个颜色矩阵——ColorMatrix,来处理这些色彩的效果,Android中的颜色矩阵是4X5的数字矩阵,他用来对颜色色彩进行处理,而对于每一个像素点,都有一个颜色分量矩阵来保存ARGB值

技术分享图片

根据前面对矩阵A、C的定义,通过矩阵乘法运算法则,可以得到:

技术分享图片

矩阵运算的乘法计算过程如下:

技术分享图片

我们观察颜色矩阵A

技术分享图片

从这个公式可以发现

  • 第一行的abcde用来决定新的颜色值R——红色
  • 第二行的fghij用来决定新的颜色值G——绿色
  • 第三行的kimno用来决定新的颜色值B——蓝色
  • 第四行的pqrst用来决定新的颜色值A——透明度
  • 矩阵A中的第五列——ejot值分别用来决定每个分量中的offset,即偏移量

通过一个小例子来讲解:
首先重新看一下矩阵变换计算公式,以R分量为例,计算过程如下:

如果让a=1,b,c,d,e都等于0,那么计算的结果为R1=R,因此我们可以构建一个矩阵

技术分享图片

如果把这个矩阵公式带入R1=AC,那么根据矩阵的乘法运算法则,可以得到R1=R。因此,这个矩阵通常是用来作为初始的颜色矩阵来使用,他不会对原有颜色进行任何变化

那么当我们要变换颜色值的时候,通常有两种方法。一个是直接改变颜色的offset,即偏移量的值来修改颜色的分量。另一种方法直接改变对应RGBA值的系数来调整颜色分量的值

从前面的分析中,可以知道要修改R1的值,只要将第五列的值进行修改即可。即改变颜色的偏移量,其它值保存初始矩阵的值,如图:

技术分享图片

在上面这个矩阵中,我们修改了R、G所对应的颜色偏移量,那么最后的处理结果就是图像的红色、绿色分别增加了100。而我们知道,红色混合绿色会得到黄色,所以最终的颜色处理结果就是让整个图片的色调偏黄色

如果修改颜色分量中的某个系数值,而其他只依然保存初始矩阵的值,如图:

技术分享图片

在上面这个矩阵中,改变了G分量所对应的系数g,这样在矩形运算后G分量会变成以前的两倍,最终效果就是图像的色调更加偏绿

下面通过实例看看如何通过矩阵改变图像的色调、饱和度和亮度:

  • 色调:setRotate(int axis, float degree),第一个参数分别使用0、1、2代表Red、Green、Blue三种颜色,第二参数需要处理的值
  • 饱和度:setSaturation(float sat),参数代表设置饱和度的值
  • 亮度:setScale(float rscale,float gscale,float bscale,float ascale),参数分别是红、绿、蓝、透明度的亮度大小值

除了单独使用上面三种方式来进行颜色效果处理之外,还提供了postConcat()方法来将矩阵的作用效果混合,从而叠加处理效果

通过SeekBar调节色调、饱和度、亮度……见经典代码回顾案例二

模拟4x5的颜色矩阵……见经典代码回顾案例三

  • 灰色效果

技术分享图片

  • 图像反转

技术分享图片

  • 怀旧效果

技术分享图片

  • 去色效果

技术分享图片

  • 高饱和度

技术分享图片

在Android中,系统系统提供了Bitmap.getPixels()方法来帮我们提取整个Bitmap中的像素点,并保存在一个数组中:

这几个参数的具体含义如下:

  • pixels:接收位图颜色值的数组
  • offset:写入到pixels[]中的第一个像素索引值
  • stride:pixels[]中的行间距
  • x:从位图中读取的第一个像素的x坐标值
  • y:从位图中读取的第一个像素的y坐标值
  • width:从每一行中读取的像素宽度
  • height:读取的行数

通常使用如下代码:

接下来获取每个像素具体的ARGB值:

接下来就是修改像素值,产生新的像素值

最后使用我们的新像素值

底片效果、老照片效果、浮雕效果……见经典代码回顾案例四

无知识点

对于图形变换,系统提供了3x3的举证来处理:

技术分享图片

与颜色矩阵一样,计算方法通过矩阵乘法:

与颜色矩阵一样,也有一个初始矩阵:

技术分享图片

图像的变形处理包含以下四类基本变换:

  • Translate:平移变换
  • Rotate:旋转变换
  • Scale:缩放变换
  • Skew:错切变换

技术分享图片

平移变换:即对每个像素点都进行平移变换,通过计算可以发现如下平移公式:

技术分享图片

旋转变换:通过以下三步骤完成以任意点为旋转中心的旋转变换

  • 将坐标原点平移到O点
  • 使用前面讲的以坐标原点为中心的旋转方法进行旋转变换
  • 将坐标原点还原

技术分享图片

缩放变换:缩放变换的效果计算公式如下

技术分享图片

错切变换:错切变换的效果计算公式如下

了解四种图形变换矩阵,可以通过setValues()方法将一个一维数组转换为图形变换矩阵:

Android中Matrix类也帮我们封装好了几个操作方法:

  • matrix.setRotate():旋转变换
  • matrix.setTranslate():平移变换
  • matrix.setScale():缩放变换
  • matrix.setSkew():错切变换
  • pre()和post():提供矩阵的前乘和后乘运算

举个例子说明前乘和后乘的不同运算方式:

  • 先平移到(300, 100)
  • 再旋转45度
  • 最后平移到(200, 200)

如果使用后乘运算,代码如下:

如果使用前乘运算,代码如下:

drawBitmapMesh()与操纵像素点来改变色彩的原理类似,只不过是把图像分成了一个个的小块,然后通过改变每一个图像块来修改整个图像:

参数分析:

  • bitmap:将要扭曲的图像
  • meshWidth:需要的横向网格数目
  • meshHeight:需要的纵向网格数目
  • verts:网格交叉点的坐标数组
  • vertOffset:verts数组中开始跳过的(X,Y)坐标对的数目

飘动的旗子……见经典代码回顾案例五

之前绘图的时候也提到过画笔的一些方法,这里就不再介绍

PorterDuffXfermod设置的是两个图层交集区域的显示方式,dst是先画的图形,而src是后画的图形

技术分享图片

以一个圆角图片为例子:

效果图,由于图片过大,只能看出一边角

技术分享图片

刮刮卡效果……见经典代码回顾案例六

Shader又被称为着色器。渲染器,它可以实现渲染,渐变等效果,Android中的Shader包括以下几种:

  • BitmapShader:位图Shader
  • LinearGradient:线性Shader
  • RadialGradient:光束Shader
  • SweepGradient:梯形Shader
  • ComposeShader:混合Shader

其中BitmapShader有三种模式可以选择:

  • CLAMP拉伸:拉伸的是图片最后的那一个像素,不断重复
  • REPEAT重复:横向,纵向不断重复
  • MIRROR镜像:横向不断翻转重复,纵向不断翻转重复

下面看下例子说明,圆形图片:

效果图

技术分享图片

下面把TileMode改为REPEAT:

技术分享图片

使用LinearGradient:

效果图

技术分享图片

结合前面的PorterDuffXfermode和刚学的LinearGradient,制作出倒影的效果图片

倒影图片效果……见经典代码回顾案例七

先上一张直观的图:

技术分享图片

Android提供的几种绘制PathEffect方式:

  • 没效果
  • CornerPathEffect:拐弯角变得圆滑
  • DiscretePathEffect:线段上会产生许多杂点
  • DashPathEffect:绘制虚线,用一个数据来设置各个点之间的间隔
  • PathDashPathEffect:绘制虚线,可以使用方形点虚线和圆形点虚线
  • ComposePathEffect:可任意组合两种路径(PathEffect)的特性

我们通过一个实例来认识这些效果:

每绘制一个Path,就将画布平移,从而让各种PathEffect依次绘制出来

技术分享图片

无知识点

View的绘制刷新间隔时间为16ms,如果在16ms内完成你所需要执行的所有操作,那么在用户视觉上,就不会产生卡顿的感觉,否则,就会出现卡顿,所以可以考虑使用SurfaceView来替代View的绘制

通常在Log会看到这样的提示:

SurfaceView与View的主要区别:

  • View主要适用于主动更新的情况下,而surfaceVicw主要适用于被动更新,例如频繁刷新
  • View在主线程中对画面进行刷新,而surfaceView通常会通过一 个子线程来进行页面的刷新
  • View在绘制时没有使用双缓冲机制,而surfaceVicw在底层实现机制中就已经实现了双缓冲机制

总结一句话就是,如果你的自定义View需要频繁刷新,或者刷新数据处理量比较大,托福机经就可以考虑使用SurfaceView替代View

SurfaceView使用步骤:

  • 创建SurfaceView继承自SurfaceView,并实现两个接口——SurfaceHolder.Callback和Runnable
  • 初始化SurfacHolder对象,并注册SurfaceHolder的回调方法
  • 通过SurfacHolder对象lockCanvas()方法获得Canvas对象进行绘制,并通过unlockCanvasAndPost(mCanvas)方法对画布内容进行提交

整个使用SurfaceView的模板代码:

唯一注意的是,在绘制中将mHolder.unlockCanvasAndPost(mCanvas)方法放到finally代码块中,保证每次都能将内容提交

正弦曲线……见经典代码回顾案例八
绘图板……见经典代码回顾案例九


技术分享图片


布局文件

Activity文件

技术分享图片


布局文件

Activity文件

关键点:将一个颜色矩阵传入画笔,然后画出原始的图在新建的图上面

技术分享图片


布局文件

Activity文件

工具类

技术分享图片


本人也是懵逼,没有搞懂这个例子

技术分享图片


技术分享图片


技术分享图片

技术分享图片

技术分享图片

经典回顾源码下载

github:https://github.com/CSDNHensen/QunYingZhuang

Android群英传知识点回顾——第六章:Android绘图机制与处理技巧

标签:map   主线程   mes   计算公式   渲染   drawtext   1.3   final   view   

原文地址:https://www.cnblogs.com/zhanglixina/p/9603847.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!