自定义控件 (?/N) - 颜料 Paint

参考来源

一、颜色

1.1 直接设置颜色

1.1.1 setColor( )

public void setColor(@ColorInt int color)

paint.setColor(Color.RED)
paint.setColor(Color.parseColor("#009688"))

1.1.2 setARGB( ) 

public void setARGB(int a, int r, int g, int b)
paint.setARGB(100, 255, 43, 1)

 1.2 设置着色器 setShader( )

Shader 着色器,设置的是一个颜色规则。使用着色器后直接设置颜色的两种方式 setColor( ) 和 setARGB( ) 就不再起作用。

public Shader setShader(Shader shader)
tile是端点范围之外的着色模式,CLAMP会在端点之外散开端点处颜色、MIRROR镜像、REPEAT重复。
线性渐变

public LinearGradient(float x0, float y0, float x1, float y1, @ColorInt int color0, @ColorInt int color1, @NonNull TileMode tile)

设置两个点和两种颜色,以这两个点为端点,使用两种颜色的渐变来绘制颜色。

辐射渐变

RadialGradient(float centerX, float centerY, float radius, @ColorInt int centerColor, @ColorInt int edgeColor, @NonNull TileMode tileMode)

centerX,centerY辐射中心坐标、radius辐射半径、centerColor中心颜色、edgeColor边缘颜色、辐射范围之外的着色模式。

扫描渐变

public SweepGradient(float cx, float cy, @ColorInt int color0, @ColorInt int color1)

cx,cy中心点坐标、color0起始颜色、color1终止颜色。

Bitmap着色器

public BitmapShader(@NonNull Bitmap bitmap, @NonNull TileMode tileX, @NonNull TileMode tileY)

tileX 横向的规则、tileY纵向的规则。

混合着色器

public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull PorterDuff.Mode mode) 

shaderA,shaderB 需要混合使用的两个着色器、mode 叠加模式即如何共同绘制。

 1.2.1 线性渐变 LinearGradient

val shader = LinearGradient(100F, 100F, 500F, 500F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP)
paint.setShader(shader)

1.2.2 辐射渐变 RadialGradient

val shader = RadialGradient(300F, 200F, 200F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"), Shader.TileMode.CLAMP)
paint.setShader(shader)

1.2.3 扫描渐变 SeepGradient

val shader = SweepGradient(300F, 300F, Color.parseColor("#E91E63"), Color.parseColor("#2196F3"))
paint.setShader(shader)

1.2.4 Bitmap着色器 BitmapShader

val bitmap = BitmapFactory.decodeResource(resources, R.drawable.betman)
val shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
paint.setShader(shader)

如果想绘制圆形的 Bitmap 就别用 drawBitmap() 改用 drawCircle()+BitmapShader 就行,其他形状同理。 

 

1.2.5 组合着色器 ComposeShader

PorterDuff.Mode 用来指定两个图像共同绘制时的颜色策略(确定两者叠加后的颜色)。可以分为两类:一类是Alpah合成,共12种,都是关于aplha通道(透明度)计算的,PorterDuff是两个共同发表算法论文人的姓。另一类是混合,Photoshop等制图软件里都有的那些模式,为了方便也被加了进来。

Alpha合成

混合

 

val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.betman)
val shader1 = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.logo)
val shader2 = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
val shader3 = ComposeShader(shader1, shader2, PorterDuff.Mode.SRC_OVER)
paint.setShader(shader3)

1.3 设置颜色过滤 setColorFilter( )

为绘制的内容设置统一的过滤策略,Canvas.drawXXX()会对每个像素进行过滤后再绘制出来。

public ColorFilter setColorFilter(ColorFilter filter)

使用的是 ColorFilter的 三个子类,见下表。

LightingColorFilter

public LightingColorFilter(@ColorInt int mul, @ColorInt int add)

模拟简单光照效果。mul用来和目标像素相乘,add用来和目标像素相加,算法:

R' = R * mul.R / 0xff + add.R
G' = G * mul.G / 0xff + add.G
B' = B * mul.B / 0xff + add.B

PorterDuffColorFilter

public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) 

使用一个指定颜色和一个指定 PorterDuff 模式来与绘制对象进行合成。color指定的颜色、mode指定的模式。(与ComposeShader不同的是只能指定颜色而不是Bitmap)

ColorMatrixColorFilter

public ColorMatrixColorFilter(@NonNull ColorMatrix matrix)

使用颜色矩阵对颜色进行处理。算法:

R' = a * R + b * G + c * B + d * A + e
G' = f * R + g * G + h * B + i * A + j
B' = k * R + l * G + m * B + n * A + o
A' = p * R + q * G + r * B + s * A + t

paint.colorFilter = LightingColorFilter(0x123456,0xABCDEF)
// R' = R * 0x12 / 0xff + 0xAB
// G' = G * 0x34 / 0xff + 0xCD
// B' = B * 0x56 / 0xff + 0xEF
LightingColorFilter(0x00ffff, 0x000000)    //去掉红色
// R' = R * 0x0 / 0xff + 0x0 = 0 
LightingColorFilter(0xffffff, 0x003000)    //绿色加强
// G' = G * 0xff / 0xff + 0x30 = G + 0x30

1.4 setXfermode( )

要绘制的内容作为源图像,View中已有的内容作为目标图像,指定一个 PorterDuff.Mode 作为绘制内容的颜色处理方案。

public Xfermode setXfermode(Xfermode xfermode)

其它子类已过时,目前只剩下PorterDuffXfermode。

1.4.1 使用离屏缓存 Off-screen Buffer

val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
...
canvas.drawBitmap(rectBitmap, 0F, 0F, paint)  //画方
paint.xfermode = xfermode
canvas.drawBitmap(CircleBitmap, 0F, 0F, paint)  //画圆
paint.xfermode = null   //用完及时清除

在第二步画圆的时候,跟它共同计算的是第一步绘制的方形。但实际上,却是整个 View 的显示区域都在画圆的时候参与计算,并且 View 自身的底色并不是默认的透明色,而且是遵循一种迷之逻辑,导致不仅绘制的是整个圆的范围,而且在范围之外都变成了黑色。 通过使用离屏缓冲,把要绘制的内容单独绘制在缓冲层, Xfermode 的使用就不会出现奇怪的结果了。

 Canvas.saveLayer( )

做短时的离屏缓存。在绘制代码的前后各加一行代码:在绘制之前保存,绘制之后恢复。

val xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
val saveLayer = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG)    //保存
canvas.drawBitmap(rectBitmap, 0F, 0F, paint)
paint.xfermode = xfermode
canvas.drawBitmap(CircleBitmap, 0F, 0F, paint)
paint.xfermode = null
canvas.restoreToCount(saveLayer)    //恢复

View.setLayerType( )

直接把整个 View 都绘制在离屏缓存中。setLayerType(LAYER_TYPE_HARDWARE) 是使用GPU缓存,setLayerType(LAYER_TYPE_SOFTWARE) 是直接用一个Bitmap缓存。无特殊要求使用上面的 Canvas.saveLayer( ) 以获取更好性能。 

1.4.2 控制好透明区域

除了使用离屏缓存,还要控制透明区域不能太小,须足够覆盖要结合绘制的内容。如下图透明区域过小而覆盖不到的地方,将不会受到 Xfermode 的影响。

二、效果

2.1 抗锯齿 setAntiAlias( )

public void setAntiAlias(boolean aa)

默认是关闭的,开启后让图形或文字的边缘更加平滑(修改图形边缘处的像素颜色使之肉眼看起来更加平滑的感觉)。推荐通过 Paint 的构造设置更便捷。

val paint = Paint(Paint.ANTI_ALIAS_FLAG) //二选一,更推荐
paint.isAntiAlias = true

2.2 绘制风格 setStyle( )

public void setStyle(Style style)

//FILL填充、STROKE画线、FILL_AND_STROKE既画线又填充。

paint.style = Paint.Style.FILL

2.3 线条形状

线条宽度

public void setStrokeWidth(float width)

单位为像素,默认0。0和1的区别见下方几何变换。

线头形状

public void setStrokeCap(Cap cap)

默认BUTT平头、ROUND圆头、SQUARE方头。

拐角形状

public void setStrokeJoin(Join join)

默认MITER尖角、 BEVEL平角、ROUND圆角。

尖角拐角延长线最大值

public void setStrokeMiter(float miter)

当拐角形状是MITER尖角时,拐角处的边缘需要使用延长线来补偿。

2.3.1 setTtrokeWidth( )

paint.strokeWidth = 3F

2.3.2 setStrokeCap( )

paint.strokeCap = Paint.Cap.ROUND

2.3.3 setStrokeJoin( )

paint.strokeJoin = Paint.Join.BEVEL

2.3.4 setStrokeMiter( )

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/17737.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Packet Tracer – 研究 VLAN 实施

Packet Tracer – 研究 VLAN 实施 地址分配表 设备 接口 IP 地址 子网掩码 默认网关 S1 VLAN 99 172.17.99.31 255.255.255.0 不适用 S2 VLAN 99 172.17.99.32 255.255.255.0 不适用 S3 VLAN 99 172.17.99.33 255.255.255.0 不适用 PC1 NIC 172.17.10.2…

数字化转型导师坚鹏:数字化转型背景下的企业人力资源管理

企业数字化转型背景下的企业人力资源管理 课程背景: 很多企业存在以下问题: 不清楚企业数字化转型目前的发展阶段与重要应用? 不知道企业数字化转型给企业人力资源管理带来哪些机遇与挑战? 不知道企业数字化转型背景下如何…

SQL注入攻防入门详解

毕业开始从事winform到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口。这几天把sql注入的相关知识整理了下,希望大家多多提意见。 (对于…

系统集成项目管理工程师 下午 真题 及考点(2020年下半年)

文章目录 2020年下半年试题一:第10章 项目质量管理,规划质量管理过程的输入试题二:第9章 项目成本管理,典型:EAC ACETC AC(BAC-EV)/CPI BAC/CPI试题三:第18章 项目风险管理&#x…

吴恩达ChatGPT网课笔记Prompt Engineering——训练ChatGPT前请先训练自己

吴恩达ChatGPT网课笔记Prompt Engineering——训练ChatGPT前请先训练自己 主要是吴恩达的网课,还有部分github的prompt-engineering-for-developers项目,以及部分自己的经验。 一、常用使用技巧 prompt最好是英文的,如果是中文的prompt&am…

【网站架构】Nginx 4层、7层代理配置,正向代理、反向代理详解

大家好,欢迎来到停止重构的频道。 本期我们讨论网络代理。 在往期《大型网站 安全性》介绍过,出于网络安全的考虑,一般大型网站都需要做网络区域隔离,以防止攻击者直接操控服务器。 网站系统的应用及数据库都会放在这个网络安全…

【Python习题集6】类与对象

类与对象 一、实验内容二、实验总结 一、实验内容 1.设计一个Circle类来表示圆,这个类包含圆的半径以及求面积和周长的函数。在使用这个类创建半径为1~10的圆,并计算出相应的面积和周长。 半径为1的圆,面积: 3.14 周长: 6.28 半径为2的圆&am…

云原生介绍

本博客地址:https://security.blog.csdn.net/article/details/130540430 一、云原生的概念 云原生的整体概念思路是三统一,即统一基础平台、统一软件架构、统一开发流程。 基于统一的基础平台、软件架构以及开发流程,数字化转型和云化转型能…

详解:搭建常见问题(FAQ)的步骤?

许多的Web用户都更加偏向于可信赖的FAQ页面,以此作为快速查找更多信息的方法。因为用户时间的紧缺,并且想知道产品的功能和能够提供的服务。构造精巧的FAQ页面是提供人们寻求信息的绝妙方法,而且还可以提供更多的信息。这就是为什么FAQ页面对…

Chrome远程调试

最近接触到Chrome远程调试相关内容,记录一下。 场景:使用Chrome远程调试Chromium。当能够控制目标主机执行命令之后,可以在该主机上建立全局代理,然后在自己这一边开启浏览器监听,接着在目标机器上执行 chrome.exe --…

3.13 结构体嵌套、大小及位域

目录 结构体嵌套结构体 结构体的大小 位域 结构体嵌套结构体 含义 结构体中的成员可以是另一个结构体 语法 struct 结构体名 { struct 结构体名 成员名; }; 结构体中共同的变量可以单独放出来,单独封装一个结构体 结构体的大小 字节对齐 含义 …

Bark:基于转换器的文本到音频模型

Bark是由Suno创建的一个基于转换器的文本到音频模型。Bark可以生成高度逼真的多语言语音以及其他音频,包括音乐、背景噪音和简单的音效。该模型还可以产生非语言交流,如大笑、叹息和哭泣。为了支持研究社区,我们正在提供对预先训练的模型检查…

【c语言】字符串的基本概念 | 字符串存储原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …

【Java EE】-博客系统(前端页面)

作者&#xff1a;学Java的冬瓜 博客主页&#xff1a;☀冬瓜的主页&#x1f319; 专栏&#xff1a;【JavaEE】 分享: 且视他人如盏盏鬼火&#xff0c;大胆地去走你的道路。——史铁生《病隙碎笔》 主要内容&#xff1a;博客系统 登陆页面&#xff0c;列表页面&#xff0c;详情页…

AArch32 AArch64 Registers map详细解析与索引

1、AArch32 Registers AArch32 系统寄存器索引。 例如第一个寄存器ACTLR点击后解析如下&#xff1a; 2、AArch64 Registers AArch64 系统寄存器索引。 3、AArch32 Operations AArch32 系统指令索引。 例如第一个寄存器ACTLR_EL1点击后解析如下&#xff1a; 4、AArch…

Inception模型实现孤立手语词的识别

实现孤立手语词的识别流程如下&#xff0c;在实际研究中&#xff0c;本章将着重研究第三阶段内容&#xff0c;也就是模型的设计与实现过程&#xff0c;目的是提高手语图像的识别准确率。 Inception模型实现 Inception模型是谷歌研究人员在2014年提出的一个深度卷…

一文把 JavaScript 中的 this 聊得明明白白

文章目录 1.this 是什么&#xff1f;2.this的指向2.1 全局上下文的 this 指向2.2 函数&#xff08;普通函数&#xff09;上下文中的 this 指向2.3 事件处理程序中的 this 指向2.4 以对象的方式调用时 this 的指向2.5 构造函数中的 this 指向2.6 在 类上下文中 this 的指向。2.7…

84.python input输入函数知识拓展

文章目录 1. input函数知识回顾2. input常犯错误解析3. 用函数转换从终端输入的数据3.1 输入的数为整数&#xff0c;则用int转换为整数3.2 输入的数为浮点数&#xff0c;则用float转换为浮点数3.3 不考虑输入的数据类型&#xff0c;则用eval函数转换 4. 变量的多种赋值方式4.1 …

【软考中级】2022下半年软件设计师案例分析题级答案

试题一(共15分) 阅读下列说明和图&#xff0c;回答问题1至问题4&#xff0c;将解答填入答题纸的对应栏内。 【说明】 随着新能源车数量的迅猛增长&#xff0c;全国各地电动汽车配套充电桩急速增长&#xff0c;同时 也带来了充电桩计量准确性的问题。充电桩都需要配备相应的…

JAVA9新特性

JAVA9新特性 概述 ​ 经过4次推迟&#xff0c;历经曲折的Java9最终在2017年9月21日发布。因为里面加入的模块化系统&#xff0c;在最初设想的时候并没有想过那么复杂&#xff0c;花费的时间超出预估时间。距离java8大约三年时间。 ​ Java 9提供了超过150项新功能特性&#x…