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

相关文章

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

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

Redis的持久化之RDB和AOF机制详解

《Redis的持久化之RDB和AOF机制详解》:本文主要介绍Redis的持久化之RDB和AOF机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核