Android群英传读书笔记第六章(Android绘图机制与处理技巧)

本文主要是介绍Android群英传读书笔记第六章(Android绘图机制与处理技巧),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

笔记

尺寸单位转换

   public static int dp2px(int dp, Context context) {return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,context.getResources().getDisplayMetrics());}public static int dip2px(int dip,Context context){float scale = context.getResources().getDisplayMetrics().density;return (int) (dip*scale+0.5f);}public static int sp2px(int sp,Context context){float scale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (sp*scale+0.5f);}

Android绘图
先看下Canvas的操作

  • save():将所有之前绘制的图像保存起来,让后续的操作好像在一个新的图层一样
  • restore():将save之后绘制的图像和save之前的图像合并。
  • translate()和rotate():画布平移旋转,也可以理解过坐标的平移旋转,这样更加好理解。

    接下来我们绘制一个表盘。
    这里写图片描述

public class ClockView extends View {Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);Paint degreePaint = new Paint(Paint.ANTI_ALIAS_FLAG);Paint hourPaint = new Paint(Paint.ANTI_ALIAS_FLAG);Paint minutePaint = new Paint(Paint.ANTI_ALIAS_FLAG);private int height;private int width;public ClockView(Context context, AttributeSet attrs) {super(context, attrs);init();}public void init(){circlePaint.setStyle(Paint.Style.STROKE);circlePaint.setStrokeWidth(5);circlePaint.setColor(Color.RED);hourPaint.setStrokeWidth(10);minutePaint.setStrokeWidth(8);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);height = getMeasuredHeight();width = getMeasuredWidth();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawCircle(width/2,height/2,width/2,circlePaint);drawDegree(canvas);drawHourAndMinute(canvas);}private void drawHourAndMinute(Canvas canvas) {canvas.save();canvas.translate(width/2,height/2);canvas.drawLine(0,0,100,100,hourPaint);canvas.drawLine(0,0,200,100,minutePaint);canvas.drawRect(0,0,20,20,hourPaint);canvas.restore();}public void drawDegree(Canvas canvas){for (int i = 0; i < 24; i++) {if(i==0||i==6||i==12||i==18){degreePaint.setStrokeWidth(5);degreePaint.setTextSize(30);canvas.drawLine(width/2,height/2-width/2,width/2,height/2 - width/2+60,degreePaint);String degree = String.valueOf(i);canvas.drawText(degree,width/2-degreePaint.measureText(degree)/2,height/2-width/2+90,degreePaint);}else{degreePaint.setStrokeWidth(3);degreePaint.setTextSize(20);canvas.drawLine(width/2,height/2-width/2,width/2,height/2 - width/2+30,degreePaint);String degree = String.valueOf(i);canvas.drawText(degree,width/2-degreePaint.measureText(degree)/2,height/2-width/2+60,degreePaint);}canvas.rotate(15,width/2,height/2);}}
}

Layer图层
通过saveLayer()来创建一个图层,基于栈的结构进行管理。
相关方法:
saveLayer();
saveLayerAlpha()
restore:()
restoreToCount()

色彩特效处理
这里写图片描述

变换颜色值的两种方法

  • 改变偏移量
  • 改变颜色系数

    颜色效果处理

  • 色调:matrix.setRotate();

  • 饱和度:matrix.setSaturation();
  • 亮度:matrix.setScale();

Android系统不允许修改原图,要先创建一个原图的副本,然后利用这个副本创建一个画布,最后把原图绘制到画布中。

  Bitmap bmp = Bitmap.createBitmap(bm.getWidth(),bm.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bmp);Paint paint  = new Paint();canvas.drawBitmap(bm,0,0,paint);

通过ColorMatrix的set方法,可以将一个一维数组转化为ColorMatrix
这里写图片描述

Android图形处理
Android的图形变换是一个3X3的矩阵,图形变化的初始矩阵也是对角线全部为1的矩阵

图形变化包含下面四个基本操作

  • 平移
  • 旋转
  • 缩放
  • 错切

Shader
- BitmapShader
- LinearGradient
- RadiaGradient
- SweepGradient
- ComposeShader

填充模式

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

    SurfaceView
    Android系统通过发出VSYNC信号来进行屏幕的重绘,刷新的时间间隔为16ms.

SurfaceView和View的区别
- View主要适用于主动更新情况,而SurfaceView主要适用于被动更新,例如频繁的刷新
- View在主线程中对画面刷新,而SurfaceView会通过一个子线程来刷新
- SurfaceView在底层实现了双缓冲机制
- 当程序需要更新View上的图像时,程序必须重绘View上显示的整张图片

如果你的自定义View需要频繁刷新,或者刷新时数据量比较大,就可以使用SurfaceView了。下面来看两个SurfaceView的例子

绘制正弦曲线

这里写图片描述

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable {private SurfaceHolder surfaceHolder;private Canvas canvas;private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//控制子线程private boolean mIsDrawing;private int x = 0;private int y;private Path mPath = new Path();public MySurfaceView(Context context, AttributeSet attrs) {super(context, attrs);surfaceHolder = getHolder();surfaceHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);setKeepScreenOn(true);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);}/*** surfaceview创建* @param holder*/@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;new Thread(this).start();}/*** surfaceview改变* @param holder* @param format* @param width* @param height*/@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}/*** surfaceview销毁* @param holder*/@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);}}public void draw(){try {canvas = surfaceHolder.lockCanvas();//设置画布背景颜色canvas.drawColor(Color.WHITE);canvas.drawPath(mPath,paint);}catch (Exception e){}finally {//对画布内容进行提交,放在finally里面可以保证执行if(canvas!=null){surfaceHolder.unlockCanvasAndPost(canvas);}}}
}

画布

这里写图片描述

public class SurfaceViewCanvas extends SurfaceView implements SurfaceHolder.Callback,Runnable {private SurfaceHolder mHolder;private Canvas canvas;private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);private boolean mIsDrawing;private Path mPath = new Path();public SurfaceViewCanvas(Context context, AttributeSet attrs) {super(context, attrs);mHolder = getHolder();mHolder.addCallback(this);setFocusable(true);setFocusableInTouchMode(true);setKeepScreenOn(true);paint.setColor(Color.RED);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(10);}@Overridepublic void surfaceCreated(SurfaceHolder holder) {mIsDrawing = true;}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {new Thread(this).start();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {mIsDrawing =false;}@Overridepublic void run() {long start = System.currentTimeMillis();while(mIsDrawing){draw();}long end = System.currentTimeMillis();if(end - start <100){try {Thread.sleep(100-(end - start));} catch (InterruptedException e) {e.printStackTrace();}}}private void draw(){try {canvas = mHolder.lockCanvas();canvas.drawColor(Color.WHITE);canvas.drawPath(mPath,paint);}catch (Exception e){}finally {if(canvas!=null){mHolder.unlockCanvasAndPost(canvas);}}}@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;}
}

与上一个例子不同的地方在于,我们对绘制的频率进行了限制,因为我们有时候不需要很频繁的绘制,这里的100mx是一个大致的经验证,这个值的范围一般在50ms到100mx之间。

这篇关于Android群英传读书笔记第六章(Android绘图机制与处理技巧)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/592450

相关文章

Java堆转储文件之1.6G大文件处理完整指南

《Java堆转储文件之1.6G大文件处理完整指南》堆转储文件是优化、分析内存消耗的重要工具,:本文主要介绍Java堆转储文件之1.6G大文件处理的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言文件为什么这么大?如何处理这个文件?分析文件内容(推荐)删除文件(如果不需要)查看错误来源如何避

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2