#前言

手把手讲解系列文章,是我写给各位看官,也是写给我自己的。
文章可能过分详细,但是这是为了帮助到尽量多的人,毕竟工作5,6年,不能老吸血,也到了回馈开源的时候.
这个系列的文章:
1、用通俗易懂的讲解方式,讲解一门技术的实用价值
2、详细书写源码的追踪,源码截图,绘制类的结构图,尽量详细地解释原理的探索过程
3、提供Github 的 可运行的Demo工程,但是我所提供代码,更多是提供思路,抛砖引玉,请酌情cv
4、集合整理原理探索过程中的一些坑,或者demo的运行过程中的注意事项
5、用gif图,最直观地展示demo运行效果

如果觉得细节太细,直接跳过看结论即可。
本人能力有限,如若发现描述不当之处,欢迎留言批评指正。

学到老活到老,路漫漫其修远兮。与众君共勉 !

#github地址:
[下载之后找到其中的 ScratchCardImageView] (https://github.com/18598925736/UiDrawTest)

#效果

#思路

上面的动态图,我们看到了一个妹纸图,然后是一个灰色的涂层,然后是 通过光标去画的时候出现的空白区域.
然后,下面会显示出当前已经刮了百分之几.

OK, 那么,按照步骤我们一步一步来绘制:


###1. 妹纸图
我猜有人可能想直接从资源文件中构建出一个Bitmap然后draw上去,没错,我之前也是这么想的,但是后来,其实有更简单的办法,让自定义View直接 AppCompatImageView,然后onDraw里面直接super.onDraw(canvas)…, 不但省了Draw原图的过程,还省了测量的过程,一举两得。

public class ScratchCardImageView extends AppCompatImageView {//省略无关代码...@Overrideprotected void onDraw(Canvas canvas) {//1 画原图super.onDraw(canvas);//这里不可以删掉。。因为画原始图片,就是这里画的//省略无关代码...}
}

然后:在布局里面直接使用它就好了:

<study.hank.com.draw001.custom.ScratchCardImageViewandroid:id="@+id/scView"android:layout_width="300dp"android:layout_height="300dp"android:src="@drawable/girl" />

###2. 刮刮卡的灰色涂层
这个时候我们只能老老实实自己写Bitmap了。代码:

    /*** 构建一个灰色图层Bitmap* @param w* @param h* @return*/private Bitmap createCoatBitmap(int w, int h) {Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);//构建一个指定宽高的bitmapCanvas canvas = new Canvas(bitmap);//新建一个画布Paint paint = new Paint();//新建画笔paint.setColor(cardColor);// 灰色paint.setAntiAlias(true);// 抗锯齿canvas.drawRect(0, 0, w, h, paint);//这个draw动作,会改变bitmap的内容return bitmap;}

在合适的地方,比如onMeasure中(因为测量,在绘制之前)调用createCoatBitmap()并且用全局变量保存它。

    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);if (!inited) {//由于onMeasure有可能会执行两次,而我们没有必要去执行两次初始化绘制,所以加一层控制//让涂层 和  图片一样宽高w = getMeasuredWidth();h = getMeasuredHeight();mCoatBitmap = createCoatBitmap(w, h);mCoatCanvas = new Canvas(mCoatBitmap);//把bitmap的内容委托给canvasinited = true;}}

#####Tips:
这里有个细节:mCoatCanvas = new Canvas(mCoatBitmap);
这句话,利用一个全局的Canvas mCoatCanvas来接收封装了mCoatBitmap的new Canvas.
因为,mCoatCanvasdrawXXX操作可以影响Bitmap的实际内容.
这里就不得不提Bitmap到底是个神马玩意了:

Bitmap,中文翻译:位图; 百度百科上对Bitmap的描述说了很多官话,其实翻译成人话就是这样的:
Bitmap,位图,点阵图。如果是一个1080x1920的位图,就是由横向1080个点 乘以 纵向1920 个像素点构成的一个矩形区域,每一个点都可以有独立的颜色(#AARRGGBB)

对,他就是每一个像素点都可以独立配色的像素点矩形。

那么为啥canvasdraw操作改变它的内容,其实也就是改变了某些像素点的颜色。
demo的试验中可以得出这个结论.
但是 源码内是如何进行的呢?开始探索源码咯:
mCoatCanvas = new Canvas(mCoatBitmap);开始

传入的bitmap被nInitRaster方法封装之后,赋值给了mNativeCanvasWrapper.

然后在真正去drawPath的时候,利用到了mNativeCanvasWrapper
熟悉C++的朋友应该知道 long类型的mNativeCanvasWrapper,只是一个对象指针,但是它能代表之前构造函数传入的Bitmap.
以此类推,看看其他的draw方法,无一例外,全都用到了mNativeCanvasWrapper

这下能解释得通了。

上面有了刮刮涂层的mCoatBitmap,那下一步就是画 刮刮涂层了:

@Overrideprotected void onDraw(Canvas canvas) {//1 画原图super.onDraw(canvas);//这里不可以删掉。。因为画原始图片,就是这里画的//省略N行...//看来drawBitmap有另外的图层保存方式int layer = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//保存当前层// 2 画涂层canvas.drawBitmap(mCoatBitmap, 0, 0, mPaint);//绘制位图只需要 l和t两个参数,已这个为左上角起点开始绘制,可能会越界//省略N行...canvas.restoreToCount(layer);// 回到指定图层}

#####TIPS:
这里又有一个细节, canvas.saveLayercanvas.restoreToCount,从命名可以知道是 保存恢复的意思:
他们的作用是,保存图层以及恢复到指定图层。由于我们这里使用了多层绘图(一层原图,一层刮涂层),而且绘制多次执行,所以必须绘制一次之后还原。具体关于saverestore,本文篇幅有限,就不详述了,可以参照 https://www.jianshu.com/p/e90accd0967f 说的很详细。

###3.光标划过之后出现的透明区域
要根据 滑动事件来绘制图形,自然离不开 onTouchEvent的重写:

看了下面的代码,应该会发现,在构建path的时候,我用了quadTo 画了二阶贝塞尔曲线,原本我想的是直接用lineTo算了,后来发现,确实有点丑,而用贝塞尔曲线,好看的多。这里没有什么技术细节,纯粹是美观原因。

    private Path mPath;//要接收手指滑过的地方,要用Path保存/*** 监控手势,改变mPath** @param e* @return*/@Overridepublic boolean onTouchEvent(MotionEvent e) {//...省略无关代码switch (e.getAction()) {case MotionEvent.ACTION_DOWN:lastX = e.getX();lastY = e.getY();mPath.moveTo(lastX, lastY);break;case MotionEvent.ACTION_MOVE: //?!!? MMP,为什么你收不到MOVE事件,只能认为是被拦截了// 手指移动,划线float endX = (lastX + e.getX()) / 2;float endY = (lastY + e.getY()) / 2;mPath.quadTo(lastX, lastY, endX, endY);lastX = endX;lastY = endY;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:break;default:break;}//...省略无关代码return super.onTouchEvent(e);//  这里有个疑问.为什么这里不是true,我就收不到move事件,是不是ImageView特有的//  MMP,原来是clickable的问题。 我在xml里面加了}

有了Path,那么就要drawPath:

@Overrideprotected void onDraw(Canvas canvas) {//1 画原图super.onDraw(canvas);//这里不可以删掉。。因为画原始图片,就是这里画的//省略无关代码...//看来drawBitmap有另外的图层保存方式int layer = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);//保存当前图层// 2 画涂层canvas.drawBitmap(mCoatBitmap, 0, 0, mPaint);//绘制位图只需要 l和t两个参数,已这个为左上角起点开始绘制,可能会越界// 3 画pathmPaint.setXfermode(xfermode);//设置模式canvas.drawPath(mPath, mPaint);//再去画//  记得要把mCoatBitmap的状态保存一下# 写在最后可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。![复习一周,字节跳动三场技术面+HR面,不小心拿了offer](https://img-blog.csdnimg.cn/img_convert/fd610dc582cb0776aec32a67e581c54d.png)![复习一周,字节跳动三场技术面+HR面,不小心拿了offer](https://img-blog.csdnimg.cn/img_convert/224f17d8693fbfca86a3a493c176013e.png)> 上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源我都在这里公开分享出来**以上我的经历希望能够给大家带来帮助,需要这些资料的朋友可以[戳这里](https://gitee.com/vip204888/java-p7),就可以免费拿到了**03639)][外链图片转存中...(img-e01xAdRs-1628441903640)]> 上面的这些(算法与数据结构)+(Java多线程学习手册)+(计算机网络顶级教程)等学习资源我都在这里公开分享出来**以上我的经历希望能够给大家带来帮助,需要这些资料的朋友可以[戳这里](https://gitee.com/vip204888/java-p7),就可以免费拿到了**

手把手讲解-一个复杂动效的自定义绘制3,膜拜大佬相关推荐

  1. Java开发知识点!手把手讲解-一个复杂动效的自定义绘制

    诶?心形是怎么绘制的? 诶?波浪是怎么画出来的,又是如何动起来的? 诶? 文字是怎么呈现出同一时刻的两种颜色的? 不知道是不是有人有这样的疑惑````请继续往下看. #效果拆解 拿到一个复杂特效,第一 ...

  2. button按钮onclick触发不了_手把手教你深入CSS实现一个粒子动效的按钮

    按钮(button)可能是网页中最常见的组件之一了,大部分都平淡无奇,如果你碰到的是一个这样的按钮,会不会忍不住多点几次呢? 转载链接: https://github.com/XboxYan/note ...

  3. 怎么实现hover_web前端CSS实现一个粒子动效的按钮

    按钮(button)可能是网页中最常见的组件之一了,大部分都平淡无奇,如果你碰到的是一个这样的按钮,会不会忍不住多点几次呢? 通常这类效果第一反应可能就是借助canvas了,比如下面这个案例点击预览( ...

  4. Android自定义View高级动效---粒子动效实现|音乐播放器粒子动效|实现酷我网易云粒子动效

    篇章目标介绍 之前看到网易云,酷我音乐都发布过用于播放器页面粒子动效的效果,于是打算自己也动手做一个,产品目标是对标酷我手机app的动效设计,实现过程完全基于自身的推测理解予以实现.计划通过两次完全完 ...

  5. 动效素材极速交付: 腾讯PAG动效组件技术揭秘

    编者按:音视频产品中的动效素材需求是源源不断的,例如贴纸花字,转场特效,照片和视频模板等,并且对它们的产量,上线速度,以及视觉效果都有比较高的要求.但在传统工作流中的交付成本却非常高,需要通过代码来手 ...

  6. 行业思考 | 酷炫动效是否利于你的产品设计?

    本文为PMCAFF专栏作者南可出品 前言 写这篇文章的起因是前段时间在Meidum上读到的一篇驳斥dribbble发展现状的文章.文章发表在16年,其中提到:"我不认为dribbble解决了 ...

  7. canvas 文字颜色_canvas 中普通动效与粒子动效的实现

    (给前端大全加星标,提升前端技能) 作者:薄荷前端 https://github.com/BooheeFE/weekly/issues/26 canvas 用于在网页上绘制图像.动画,可以将其理解为画 ...

  8. uniapp image图片切换动效_谷歌设计团队发布了一款动效神器,让 UI 和动效无缝打通...

    编者按:Google 设计团队为了更好地推进 UI 和动效设计,自己开发过不少新的工具,打通 Sketch2AE 是其中之一,如今的 AEUX 也是为了相似的目的而存在的一个全新升级的动效工具~ 动效 ...

  9. 每日一篇系列---CSS3实现下雨动效

    今日份笔记,下雨动效. 先前实现类似的天气动效,都是麻烦UI大佬给做的图,这次使用CSS3来实现一个. 一.准备工作 首先介绍下实现主要会用到的CSS3属性:box-shadow box-shadow ...

最新文章

  1. C# 指定字符串截取方法
  2. FPN(Feature Pyramid Network)多尺度目标检测方案
  3. 关于虚拟机vmware三种网络模式
  4. kubernetes ui 搭建
  5. c语言100以内加减乘除法,一百以内的加减乘除法游戏....
  6. oracle 删序列,oracle创建和删除序列
  7. MeteoInfoLab脚本示例:OMI Grid HDF数据
  8. PyTorch:模型训练-模型参数parameters
  9. Android系统和内核编译命令
  10. atitit.提升开发效率---动态语言总结
  11. telegram bots 开发者文档 简介
  12. Flutter sksl 着色器预热
  13. windows如何设置软件开机启动
  14. 域名带www和不带的区别
  15. iOS中常用的颜色色值
  16. 移动机器人c语言程序设计,机器人辅助C程序设计
  17. 爱上经典之《大公鸡》
  18. 三、cadence ic 5141 ——打开cadence软件
  19. 广告投放ROI如何计算?实现广告效果最大化
  20. pom文件分析(笔记)

热门文章

  1. 可编程电子安全相关系统_编程中的安全生态系统概述
  2. hadoop2.6.0 完全分布式安装教程
  3. 淘宝接口(通过ip获取信息)
  4. 只为让你听见更好的声音 吉利缤瑞音响升级牧童套餐喇叭
  5. KMP字符串匹配 洛古3375 kmp水题
  6. UPPAAL怎么使用
  7. 无心剑中译里尔克《秋日》
  8. Ubantu安装KDE桌面环境_下载KDE主题
  9. Linux离线升级redis-6.2.7
  10. 将qDebug()信息重定向到文件中