本章将介绍关于Andorid绘图机制的一些高级技巧与分析

6.1、屏幕的尺寸信息

一般我们以720x1280为标准原稿,那么1dp = 2px

6.2、2D绘图基础

Canvas提供了很多api
如:

drawPoint(点)drawLine(线)drawRect(矩形)drawVertices(多边形)drawarc(弧形)drawCircle(圆)

Paint作为画笔,也提供了很多api

如:

setAntiAlias() //设置画笔的锯齿效果
setColor//设置画笔的颜色
setARGB()//设置画笔的ARGB值
setAlpha()//设置画笔的透明度
setStyle()//设置画笔的风格

绘图api+画笔api,就可以画出任意的图形了

6.3、Andorid XML绘图

1、bitmap
2、shape
3、layer(图层效果)
4、Selector(按下,抬起的效果)

6.4、Andorid 绘图技巧

Canvas作为绘图直接的对象,提供了几个有用的方法
Canvas.save  保存
Canvas.restore 与save之前的图像合并
Canvas.translate 平移
Canvas.rotate 旋转

下面我们创建一个仪表盘:

我们分析下这个图形:
1、仪表盘——外面的大圆盘
2、刻度线——4个长的刻度线和其他短的刻度线
3、刻度值——长刻度线对应的大刻度值和其他小刻度值
4、指针——一粗一细2根指针

圆盘:canvas.drawCircle()绘制一个圆就可以了
刻度线:直角线直接确定2点坐标就可以了,斜线就要通过三角函数实现了,不,可以利用旋转角度实现,每画一条线就旋转相应的角度,然后把画布再重新还原到旋转前的位置
指针:通过translate 方法来进行平移
完整代码如下:

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);}@Overrideprotected 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,mWidth / 2, mHeight / 2 - mWidth / 2 + 60,painDegree);String degree = String.valueOf(i);canvas.drawText(degree,mWidth / 2 - painDegree.measureText(degree) / 2,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);}// 画圆心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();}
}

6.4.2 Layer图层

saveLayer()——创建图层
saveLayerAlpha——入栈
restore()和restoreToCount()——出栈

例如在onDraw方法中绘制2个相交重合的圆

我们要知道:
图层透明度是0~255不同的数值
127为半透明
255完全不透明
0完全透明

6.4、Andorid 图像处理之色彩特效处理

在Andorid中封装了一个类:ColorMatrix来控制色调、饱和度、亮度

色调:setRotate(int a,float b)
a:系统用0,1,2来代表Red,Green,Blue三种颜色的处理
b:需要处理的值饱和度:setSaturation(float a)
a :饱和度的值亮度:setScale

最后系统也提供了postConcat()将效果混合

ColorMatrix   cm = new ColorMatrix();
cm. postConcat(matrix1);
cm. postConcat(matrix2);
cm. postConcat(matrix3);

下面我们写个例子:通过seekBar来改变不同的数值,来控制整个图片里面的这3个数值

完整代码如下:

package com.imooc.myapplication;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;public class PrimaryColor extends Activity implements SeekBar.OnSeekBarChangeListener {private static int MAX_VALUE = 255;private static int MID_VALUE = 127;private ImageView mImageView;private SeekBar mSeekbarhue, mSeekbarSaturation, mSeekbarLum;private float mHue, mStauration, mLum;private Bitmap bitmap;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.primary_color);bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test3);mImageView = (ImageView) findViewById(R.id.imageview);mSeekbarhue = (SeekBar) findViewById(R.id.seekbarHue);mSeekbarSaturation = (SeekBar) findViewById(R.id.seekbarSaturation);mSeekbarLum = (SeekBar) findViewById(R.id.seekbatLum);mSeekbarhue.setOnSeekBarChangeListener(this);mSeekbarSaturation.setOnSeekBarChangeListener(this);mSeekbarLum.setOnSeekBarChangeListener(this);mSeekbarhue.setMax(MAX_VALUE);mSeekbarSaturation.setMax(MAX_VALUE);mSeekbarLum.setMax(MAX_VALUE);mSeekbarhue.setProgress(MID_VALUE);mSeekbarSaturation.setProgress(MID_VALUE);mSeekbarLum.setProgress(MID_VALUE);mImageView.setImageBitmap(bitmap);}@Overridepublic void onProgressChanged(SeekBar seekBar,int progress, boolean fromUser) {switch (seekBar.getId()) {case R.id.seekbarHue:mHue = (progress - MID_VALUE) * 1.0F / MID_VALUE * 180;break;case R.id.seekbarSaturation:mStauration = progress * 1.0F / MID_VALUE;break;case R.id.seekbatLum:mLum = progress * 1.0F / MID_VALUE;break;}mImageView.setImageBitmap(ImageHelper.handleImageEffect(bitmap, mHue, mStauration, mLum));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><ImageViewandroid:id="@+id/imageview"android:layout_width="300dp"android:layout_height="300dp"android:layout_centerHorizontal="true"android:layout_marginBottom="24dp"android:layout_marginTop="24dp" /><SeekBarandroid:id="@+id/seekbarHue"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/imageview" /><SeekBarandroid:id="@+id/seekbarSaturation"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/seekbarHue" /><SeekBarandroid:id="@+id/seekbatLum"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/seekbarSaturation" /></RelativeLayout>

6.4、Andorid 图像处理之图形特效处理

图像的变形处理通常有4类:

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

Android使用Matrix来封装矩阵变换:

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

拓展:drawBitmapMesh方法可以创建很多负责的图形特效

6.7、Andorid 图像处理之图形特效处理

6.7.1、porterDuffXfermode来实现刮刮乐

完整代码如下:

package com.imooc.myapplication;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;public class XfermodeView extends View {private Bitmap mBgBitmap, mFgBitmap;private Paint mPaint;private Canvas mCanvas;private Path mPath;public XfermodeView(Context context) {super(context);init();}public XfermodeView(Context context, AttributeSet attrs) {super(context, attrs);init();}public XfermodeView(Context context, AttributeSet attrs,int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mPaint = new Paint();mPaint.setAlpha(0);mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeJoin(Paint.Join.ROUND);mPaint.setStrokeWidth(50);mPaint.setStrokeCap(Paint.Cap.ROUND);mPath = new Path();mBgBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.test);mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(),mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);mCanvas = new Canvas(mFgBitmap);mCanvas.drawColor(Color.GRAY);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath.reset();mPath.moveTo(event.getX(), event.getY());break;case MotionEvent.ACTION_MOVE:mPath.lineTo(event.getX(), event.getY());break;}mCanvas.drawPath(mPath, mPaint);invalidate();return true;}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawBitmap(mBgBitmap, 0, 0, null);canvas.drawBitmap(mFgBitmap, 0, 0, null);}
}

注意:在绘图时,将硬件加速关闭,有些模式不支持硬件加速

6.7.2、Shader 着色器、渲染器

BitmapShader——位图Shader
LinearGradient——线型Shader
RadialGradient——光速Shader
SweepGradient——梯度Shader
ComposeShader——混合Shader

6.7.3、PathEffect 绘制路径

6.8、View的孪生兄弟:SurfaceView

在View的绘制过程中,处理的逻辑太多容易耗时,为了避免这个问题,andorid提供SurfaceView来解决这个问题
总结:
如果你的自定义view需要频繁的刷新,或者刷新时数据处理量比较大,那么就可以使用surfaceview取代view了。

自定义surface接口需要实现2个接口SurfaceHolder.Callback和Runnable
SurfaceHolder.Callback接口对应创建、改变、销毁的过程
通常需要定义3个成员变量

// SurfaceHolder
private SurfaceHolder mHolder;
// 用于绘图的Canvas
private Canvas mCanvas;
// 子线程标志位
private boolean mIsDrawing;

完整代码如下:

package com.imooc.surfaceviewtest;import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class SurfaceViewTemplate extends SurfaceViewimplements SurfaceHolder.Callback, Runnable {// SurfaceHolderprivate SurfaceHolder mHolder;// 用于绘图的Canvasprivate Canvas mCanvas;// 子线程标志位private boolean mIsDrawing;public SurfaceViewTemplate(Context context) {super(context);initView();}public SurfaceViewTemplate(Context context, AttributeSet attrs) {super(context, attrs);initView();}public SurfaceViewTemplate(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initView();}private void initView() {//1、初始化SurfaceHoldermHolder = getHolder();mHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);//mHolder.setFormat(PixelFormat.OPAQUE);}//创建@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;//开启子线程进行绘制new Thread(this).start();}//改变@Overridepublic void surfaceChanged(SurfaceHolder holder,int format, int width, int height) {}//销毁@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {//不停的绘制while (mIsDrawing) {draw();}}private void draw() {try {mCanvas = mHolder.lockCanvas();// draw sth} catch (Exception e) {} finally {if (mCanvas != null)//对画布内容进行提交mHolder.unlockCanvasAndPost(mCanvas);}}
}

注意:在绘制方法中将mHolder.unlockCanvasAndPost(mCanvas);方法放在finally代码块中,来保证每次都能将内容提交。

6.8.3、SurfaceView绘图实例

实例一:绘制正弦曲线
不断的修改横纵坐标的值

完整代码如下:

package com.imooc.surfaceviewtest;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class SinView extends SurfaceViewimplements SurfaceHolder.Callback, Runnable {private SurfaceHolder mHolder;private Canvas mCanvas;private boolean mIsDrawing;private int x = 0;private int y = 0;private Path mPath;private Paint mPaint;public SinView(Context context) {super(context);initView();}public SinView(Context context, AttributeSet attrs) {super(context, attrs);initView();}public SinView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initView();}private void initView() {mHolder = getHolder();mHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);mPath = new Path();mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(10);mPaint.setStrokeCap(Paint.Cap.ROUND);mPaint.setStrokeJoin(Paint.Join.ROUND);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;mPath.moveTo(0, 400);new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder,int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {while (mIsDrawing) {draw();x += 1;y = (int) (100*Math.sin(x * 2 * Math.PI / 180) + 400);mPath.lineTo(x, y);}}private void draw() {try {mCanvas = mHolder.lockCanvas();// SurfaceView背景mCanvas.drawColor(Color.WHITE);mCanvas.drawPath(mPath, mPaint);} catch (Exception e) {} finally {if (mCanvas != null)mHolder.unlockCanvasAndPost(mCanvas);}}
}

实例二:

完整代码如下:

package com.imooc.surfaceviewtest;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;public class SimpleDraw extends SurfaceViewimplements SurfaceHolder.Callback, Runnable {private SurfaceHolder mHolder;private Canvas mCanvas;private boolean mIsDrawing;private Path mPath;private Paint mPaint;public SimpleDraw(Context context) {super(context);initView();}public SimpleDraw(Context context, AttributeSet attrs) {super(context, attrs);initView();}public SimpleDraw(Context context, AttributeSet attrs,int defStyle) {super(context, attrs, defStyle);initView();}private void initView() {mHolder = getHolder();mHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);this.setKeepScreenOn(true);mPath = new Path();mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(40);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}@Overridepublic void surfaceChanged(SurfaceHolder holder,int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing = false;}@Overridepublic void run() {long start = System.currentTimeMillis();while (mIsDrawing) {draw();}long end = System.currentTimeMillis();// 50 - 100if (end - start < 100) {try {Thread.sleep(100 - (end - start));} catch (InterruptedException e) {e.printStackTrace();}}}private void draw() {try {mCanvas = mHolder.lockCanvas();mCanvas.drawColor(Color.WHITE);mCanvas.drawPath(mPath, mPaint);} catch (Exception e) {} finally {if (mCanvas != null)mHolder.unlockCanvasAndPost(mCanvas);}}@Overridepublic boolean onTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mPath.moveTo(x, y);break;case MotionEvent.ACTION_MOVE:mPath.lineTo(x, y);break;case MotionEvent.ACTION_UP:break;}return true;}
}

第六章Android绘图机制与处理技巧(Android群英传)相关推荐

  1. android 特效绘图,Android绘图机制与处理技巧——Android图像处理之图形特效处理...

    Android变形矩阵--Matrix 对于图像的图形变换,Android系统是通过矩阵来进行处理的,每个像素点都表达了其坐标的X.Y信息.Android的图形变换矩阵是一个3x3的矩阵,如下图所示: ...

  2. Android群英传》读书笔记 (3) 第六章 Android绘图机制与处理技巧 + 第七章 Android动画机制与使用技巧...

    第六章 Android绘图机制与处理技巧 1.屏幕尺寸信息 屏幕大小:屏幕对角线长度,单位"寸": 分辨率:手机屏幕像素点个数,例如720x1280分辨率: PPI(Pixels ...

  3. Android绘图机制与处理技巧-更新中

    概述 这里我们主要来探讨下 Android屏幕的相关只是 Android绘图技巧 Android图像处理技巧 SurfaceView的使用 绘图技巧中,医生讲的比较粗略,更多的细节参考了 Keegan ...

  4. Android绘图机制(三)——自定义View的实现方式以及半弧圆新控件

    Android绘图机制(三)--自定义View的三种实现方式以及实战项目操作 在Android绘图机制(一)--自定义View的基础属性和方法 里说过,实现自定义View有三种方式,分别是 1.对现有 ...

  5. Android绘图机制 Demo(简单完成美图秀秀的滤镜)

    Android绘图机制 Demo(简单完成美图秀秀的滤镜) 1.xml <?xml version="1.0" encoding="utf-8"?> ...

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

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

  7. Android 动画机制与使用技巧

    动画效果一直是人机交互中非常重要的部分,与死板.突兀的显示效果不同,动画效果的加入,让交互变得更加友好,特别是在提示.引导类的场景中,合理地使用动画能让用户获得更加愉悦的使用体验 一.Android ...

  8. Android安全机制(2) Android Permission权限控制机制

    http://blog.csdn.net/vshuang/article/details/44001661 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 1.概述 Andro ...

  9. Android伸手党系列之六:Android开发进阶

    这是android伸手党知识收集系列的第六篇,来整理android开发进阶相关知识:Window,View,事件分发,NFC,蓝牙等. Android View 简介 View的简介 那些你应该知道却 ...

最新文章

  1. 带无线驱动的linux版本,怎么在Linux里查询无线网卡的驱动程序版本
  2. tomcat安装配置及应用
  3. 网站内容批量抓取和《著作权法》
  4. 力压今日头条成 App Store 榜第一,个税 App 惊爆 62 例木马病毒!
  5. 计算机组成原理—指令格式
  6. Sentry的安装搭建与使用
  7. 【SpringBoot_ANNOTATIONS】组件注册 01 @Configuration @Bean
  8. Allwinner ClassA20类库分析
  9. paypal android sdk,Android Paypal SDK错误:商家不接受此类付款
  10. windows批量修改文件后缀名
  11. android源代码居中字体,一篇文章了解移动端文本垂直居中
  12. 推荐的这22个高频 CLI 工具,确定不收藏吗?
  13. 虚拟机安装pycharm
  14. 关于我对网赚的思路,赚钱的方法透露
  15. Arduino ESP32将数据保存到NVS中
  16. VB利用API画线性渐变矩形
  17. 因果推断——现代统计的思想飞跃
  18. python发送邮件 SMTP socks代理
  19. 一种基于Tent混沌映射初始化种群的改进灰狼算法
  20. php gtk中文介绍,学习php-gtk2之hello world

热门文章

  1. Php禁止外部盗链nginx,php如何禁止外部盗链
  2. 无限火力更新服务器公告,lol无限火力2019时间表官方公告一览 无限火力活动时间怎么查地址...
  3. Android 光芒四射的View
  4. Matplotlib画图最全小白教程,代码+贴图保你看懂,都总结下来了,再无更全!
  5. 蓝桥杯-——罗马数字的暴力破解
  6. 【python基础】pyecharts入门
  7. [日记]买了个联想Y460笔记本
  8. 计算机网络常使用的带宽单位,计算机网络常用的7个性能指标
  9. BM3D 灰度图像和彩色图像去噪实现
  10. 面向6G的可重构智能表面部署与应用思考