诶?心形是怎么绘制的?
诶?波浪是怎么画出来的,又是如何动起来的?
诶? 文字是怎么呈现出同一时刻的两种颜色的?

不知道是不是有人有这样的疑惑````请继续往下看.

#效果拆解

拿到一个复杂特效,第一件事不要慌,先仔细分析一下,这个特效里面具体有哪些细节可以拆分出来。复杂的东西都是由简单的细节 组合而成。

开始拆解。
1、绘制区域是一个心形
2、波浪从最下面开始,逐渐用绿色填充了整个心形
3、中间有文字内容“一条大灰狼”,并且在波浪增长的过程中,文字存在一段时间的上下两部分颜色不同的状态.

#本案例用到的知识点:

1、canvas.clipPath 画布裁剪
2、canvas.save 画布状态保存
3、canvas.restore 恢复
4、canvas.translate 画布平移
6、path.rCubicTo 构建三阶贝塞尔曲线(相当于上一个点位置)
5、属性动画 ValueAnimator / AnimatorSet

#开始撸码
按照之前拆解的步骤,

###第1步:构建一个心形区域

当一个复杂图形摆在我们面前,而且还是不规则图形,我们首先应该想到的,就是android.graphics.Path 类,它可以记录复杂图形的全部点组成的路径。
关键代码:

/*** 构建心形* <p>* 注意,它这个是以 矩形区域中心点为基准的图形,所以绘制的时候,必须先把坐标轴移动到 区域中心*/private void initHeartPath(Path path) {List<PointF> pointList = new ArrayList<>();pointList.add(new PointF(0, Utils.dp2px(-38)));pointList.add(new PointF(Utils.dp2px(50), Utils.dp2px(-103)));pointList.add(new PointF(Utils.dp2px(112), Utils.dp2px(-61)));pointList.add(new PointF(Utils.dp2px(112), Utils.dp2px(-12)));pointList.add(new PointF(Utils.dp2px(112), Utils.dp2px(37)));pointList.add(new PointF(Utils.dp2px(51), Utils.dp2px(90)));pointList.add(new PointF(0, Utils.dp2px(129)));pointList.add(new PointF(Utils.dp2px(-51), Utils.dp2px(90)));pointList.add(new PointF(Utils.dp2px(-112), Utils.dp2px(37)));pointList.add(new PointF(Utils.dp2px(-112), Utils.dp2px(-12)));pointList.add(new PointF(Utils.dp2px(-112), Utils.dp2px(-61)));pointList.add(new PointF(Utils.dp2px(-50), Utils.dp2px(-103)));path.reset();for (int i = 0; i < 4; i++) {if (i == 0) {path.moveTo(pointList.get(i * 3).x, pointList.get(i * 3).y);} else {path.lineTo(pointList.get(i * 3).x, pointList.get(i * 3).y);}int endPointIndex;if (i == 3) {endPointIndex = 0;} else {endPointIndex = i * 3 + 3;}path.cubicTo(pointList.get(i * 3 + 1).x, pointList.get(i * 3 + 1).y,pointList.get(i * 3 + 2).x, pointList.get(i * 3 + 2).y,pointList.get(endPointIndex).x, pointList.get(endPointIndex).y); //你的心形就是用贝塞尔曲线来画的吗}path.close();path.computeBounds(mHeartRect, false);//把path所占据的最小矩形区域,返回出去}

传入一个Path引用,然后在方法内部对path进行各种api调用改变其属性. 这里需要提及一个重点:最后一行代码 path.computeBounds(mHeartRect, false); 意思是,无论什么样的path,它都会占据一个最小矩形区域,computeBounds方法可以获取这个矩形区域,设置给入参mHeartRect.

###第2步:将心形区域裁剪出来, 裁剪之后,后续的绘制都只会显示在这个区域之内

(为了作图方便,我们通常先把坐标轴原点移动到 绘制区域的正中央)

    @Overrideprotected void onDraw(Canvas canvas) {int width = getWidth();int height = getHeight();canvas.translate(width / 2, height / 2);//为了作图方便,我们通常先把坐标轴原点移动到 绘制区域的正中央...省略无关代码canvas.clipPath(mMainPath);//裁剪心形区域canvas.save();//保存画布状态...省略无关代码}

###第3步:绘制波浪区域

这里有两点细节
1)波浪区域分为两块,topbottom 上下两块
2) 整个波浪区域的长度为 心形矩形范围宽度的2
(?为什么是2倍?因为上面的波浪动画,其实是整个波浪区域平移造成的视觉效果,为了让这个动画可以无限执行,设计两倍宽度,当一半的宽度向右移动刚好触及心形矩形区域的右边框的时候,让它还原到原始位置,这样就能无缝衔接。)

######关键代码1 - 波浪path的构建

    /*** @param ifTop   是否是上部分; 上下部分的封口位置不一样* @param r       心形的矩形区域* @param process 当前进度值*/private void resetWavePath(boolean ifTop, RectF r, float process, Path path) {final float width = r.width();final float height = r.width();path.reset();if (ifTop) {path.moveTo(r.left - width, r.top);} else {path.moveTo(r.left - width, r.bottom); //下部,初始位置点在 下}float waveHeight = height / 8f;//波动的最大幅度//找到矩形区域的左边线中点path.lineTo(r.left - width, r.bottom - height * process);//做两个周期的贝塞尔曲线for (int i = 0; i < 2; i++) {float px1, py1, px2, py2, px3, py3;px1 = width / 4;py1 = -waveHeight;px2 = width / 4 * 3;py2 = waveHeight;px3 = width;py3 = 0;path.rCubicTo(px1, py1, px2, py2, px3, py3);}if (ifTop) {path.lineTo(r.right, r.top);} else {path.lineTo(r.right, r.bottom);}path.close();}

######关键代码2- 属性动画 改变两个全局变量 波浪的向上增长系数 以及 横向波浪动画系数

    AnimatorSet animatorSet;// 动起来public void startAnimator() {if (animatorSet == null) {animatorSet = new AnimatorSet();ValueAnimator growAnimator = ValueAnimator.ofFloat(0f, 1f);growAnimator.addUpdateListener(animation -> growProcess = (float) animation.getAnimatedValue());growAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {animatorSet.cancel();}});growAnimator.setInterpolator(new DecelerateInterpolator());growAnimator.setDuration((long) (4000 / animatorSpeedCoefficient));ValueAnimator waveAnimator = ValueAnimator.ofFloat(0f, 1f);waveAnimator.setRepeatCount(ValueAnimator.INFINITE);waveAnimator.setRepeatMode(ValueAnimator.RESTART);waveAnimator.addUpdateListener(animation -> {waveProcess = (float) animation.getAnimatedValue();invalidate();});waveAnimator.setInterpolator(new LinearInterpolator());waveAnimator.setDuration((long) (1000 / animatorSpeedCoefficient));animatorSet.playTogether(growAnimator, waveAnimator);animatorSet.start();} else {animatorSet.cancel();animatorSet.start();}}

######关键代码3- 利用属性动画改变的全局变量,构建动态效果

    @Overrideprotected void onDraw(Canvas canvas) {int width = getWidth();int height = getHeight();canvas.translate(width / 2, height / 2);//为了作图方便,我们通常先把坐标轴原点移动到 绘制区域的正中央curXOffset = waveProcess * mHeartRect.width();//当前X轴方向上 波浪偏移量canvas.clipPath(mMainPath);canvas.save();mainRect = new Rect();... 省略无关代码// 上波浪区域resetWavePath(true, mHeartRect, growProcess, topWavePath);canvas.translate(curXOffset, 0);canvas.clipPath(topWavePath);canvas.drawPath(topWavePath, mTopPaint);... 省略无关代码//下波浪区域resetWavePath(false, mHeartRect, growProcess, bottomWavePath);canvas.restore();canvas.translate(curXOffset, 0);canvas.clipPath(bottomWavePath);canvas.drawPath(bottomWavePath, mBottomPaint);## 总结在清楚了各个大厂的面试重点之后,就能很好的提高你刷题以及面试准备的效率,接下来小编也为大家准备了最新的互联网大厂资料。> **[资料领取:点我即可免费领取](https://gitee.com/vip204888/java-p7)**![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/25a3b885454d37327e5bdb3af8506264.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/8828fee8ce9a85311f9e2567697e51e7.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/bf4e388512366b3d75080d24f4cedd0c.png)以及面试准备的效率,接下来小编也为大家准备了最新的互联网大厂资料。> **[资料领取:点我即可免费领取](https://gitee.com/vip204888/java-p7)**[外链图片转存中...(img-IBI2XtRt-1628134811223)][外链图片转存中...(img-XbeTksXa-1628134811226)][外链图片转存中...(img-GDnHn72b-1628134811227)]![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/5817ced066f0cc9032533d791b056f10.png)

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

  1. 手把手讲解-一个复杂动效的自定义绘制3,膜拜大佬

    #前言 手把手讲解系列文章,是我写给各位看官,也是写给我自己的. 文章可能过分详细,但是这是为了帮助到尽量多的人,毕竟工作5,6年,不能老吸血,也到了回馈开源的时候. 这个系列的文章: 1.用通俗易懂 ...

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

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

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

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

  4. 基于JAVA开发使用IDEA兼容Eclipse的动漫视屏网站

    基于IDEA兼容Eclipse开发的动漫视屏网站 这是一个适合毕设和课程设计的网站开发 需求分析: 效果图 本地搭建教程 数据库的逆向模型 主要的代码 这是一个适合毕设和课程设计的网站开发 需求分析: ...

  5. 用eclipse玩转Python,让习惯java开发的童鞋拥有一个更爽的开发体验

    #0>>>>>>>预准备工作:(a标签貌似不能用,,只好比较lowbi的直接放地址) IDE eclipse 下载地址: http://ftp.yz.yama ...

  6. java 开发vr_手把手教你搭建虚拟现实AR/VR开发环境

    ❗前情提要: 注意!软件安装路径下不能有中文! 软件提取: 1.安装Unity3d 先后安装: UnitySetup64-5.6.2f1 UnityStandardAssetsSetup-5.6.2f ...

  7. java开发台球的图片_Java模拟桌球打击处理及绘制

    Java模拟桌球打击处理及绘制 由于Java可以很轻易的完成比较复杂的数学运算,所以我们经常能看到物理领域的问题借助Java实现效果演示,下面我给出一个桌球碰撞的处理及绘制实例. package or ...

  8. java开发简单解释器,实现一个简单的解释器(5)

    你如何处理和了解像创建解释器或编译器这样复杂的事情?在开始时,一切看上去都像是一团乱七八糟的纱线,你需要解开缠结才能得到完美的球. 到达那里的方法是将它解开一个线,一次解开一个结.不过有时候,你可能会 ...

  9. Java开发知识点!mysql运行sql文件很慢

    MySQL为何不选择平衡二叉树 既然平衡二叉树解决了普通二叉树的问题,那么mysql为何不选择平衡二叉树作为索引呢? 索引需要存储什么 让我们想一想,如果我们要把索引存起来,那么应该存哪些信息呢,它应 ...

最新文章

  1. SQL基础:常用SQL语句详解(转)
  2. JZOJ__Day 10:【普及模拟】【USACO】横幅
  3. MybatisPlus代码生成器配置
  4. 打开高效文本编辑之门_Linux Sed插入追加转换退出等命令应用
  5. 把linux制作成内存系统,把内存当硬盘,提速你的linux系统
  6. hibernate防止sql注入对参数赋值传参数的例子
  7. 快来加入阿里云大学【云学院】班级助理招募—机会稍纵即逝,错过遥遥无期!...
  8. vtkSuperquadricSource:创建以原点为中心的多边形超二次曲面
  9. linux 服务管理
  10. python项目实践_python实践项目
  11. Linux创建用户、用户组 及 删除
  12. Eclipse中与CVS相连的工程中的文件,不显示版本信息时,如何处理(重启Eclipse)!
  13. 再谈设计模式之-1.单例模式
  14. Android与物联网设备通信-网络模型分层
  15. 决胜新能源汽车战场:价格拖死战、舆论声量战、产业兼并战
  16. 《企业IT架构转型之道》阿里巴巴中台战略思想和架构实战-书摘整理
  17. 图解机器学习算法(1) | 机器学习基础知识(机器学习通关指南·完结)
  18. java4.25生成车牌号_泸牌16年涨882倍 超25万人拍一张车牌为哪般?
  19. 查理芒格推荐的100个思维模型
  20. 教你10分钟电脑配置挑选装机速成攻略

热门文章

  1. Tensor for ‘out‘ is on CPU, Tensor for argument #1 ‘self‘ is on CPU
  2. hk.module must be initialized inside an hk.transform
  3. MediaSource 非当前窗口
  4. pytorch nan解决方法笔记
  5. NoBrokersAvailableError
  6. 图像的低频是轮廓,高频是噪声和细节 小波变换
  7. python中文转拼音
  8. Freetype library not found问题解决
  9. 基于标记的AR的OpenCV实现
  10. php如何实现用户报警,php封装实现钉钉机器人报警接口的示例代码