前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自定义View+属性动画实战 — 灵动的锦鲤

自定义View+属性动画实战 — 灵动的锦鲤

作者头像
没关系再继续努力
发布2021-12-15 16:15:45
5850
发布2021-12-15 16:15:45
举报
文章被收录于专栏:Android面试

通过自定义View+属性动画 实现一个会动鱼

59904AE41.gif
59904AE41.gif

分析:

1.画一条鱼

2.鱼原地动

3.鱼向点击处游动

画一条鱼

image.png
image.png

鱼分为:鱼头(圆) + 身体(两条直线+两条贝塞尔曲线) + 鱼鳍(一条直线+一个贝塞尔)+尾巴(两三角)+节肢*2 (梯形+两圆)

image.png
image.png

先把鱼水平朝右,画一个坐标系,鱼的重心为坐标系中心

image.png
image.png
  1. 先定下鱼的重心的坐标

头圆半径的4.19倍,这个其实是自己定的,5f,6f都行,就是只改变鱼的长度,用鱼头半径做初始单位有利于改变整个鱼的大小。

image.png
image.png
  1. 因为重心坐标定下了,所以整个鱼的母布局ImageView的宽高,重心的两倍(鱼左右转都不会超出边界)
image.png
image.png
  1. 重点!求一个点的坐标。已知一个点、夹角、长度。求一个点的坐标

初中知识:

V.JPG
V.JPG

所以可以得出:入参一个点、两点长度、对于x轴的角度。返回值 一个坐标

image.png
image.png
  1. 根据这个方程求解各个鱼身体。

定义画笔

mPaint.setDither(true);防抖动

mPaint.setAntiAlias(true); 抗锯齿

image.png
image.png

画鱼头:找到鱼头圆心,入参:重心、鱼身长一半、鱼的朝向(默认180跟重心一个方向)

image.png
image.png

画鱼鳍

鱼鳍是一个直线+一个二阶贝塞尔曲线,所以重点就是求出三个点:鱼鳍左点、右点、贝塞尔控制点

image.png
image.png

通过鱼头的圆心求,距离 0.9 * R ,角度110 。通过那个公式就能求出来 = 右鱼鳍点

左鱼鳍点 = 右鱼鳍点、距离、角度-180

贝塞尔控制点 = (这个完全靠自己试,只影响鱼鳍的胖瘦) 右鱼鳍点、距离 * 1.8f、角度 115

试贝塞尔的网站:cubic-bezier.com/#.17,.67,.8…

image.png
image.png
image.png
image.png

三个点都有了,绘制鱼鳍:

绘制之前要将其他绘制重置: mPath.reset();

然后mPath.moveTo()移动到第一个点

mPath.lineTo()画直线

mPath.quadTo()画二阶贝塞尔曲线,入参第二个点、第三个点

最后 canvas.drawPath(mPath,mPaint);直接画出来

最后一个点不用封闭,系统自动会封闭。

image.png
image.png

别的部分也都差不多,根据那个公式,通过参考点求出另一个点,然后求出各个部分的点,最后连线画就行

求出各个点
image.png
image.png

然后

mPath.reset()、 mPath.moveTo、 mPath.lineTo、canvas.drawPath

image.png
image.png

画身体

求出这6个点就行

image.png
image.png
image.png
image.png

鱼原地摆动

鱼原地摆动需要属性动画ValueAnimator

ValueAnimator

属性动画,给一个值,一直变,

如: ValueAnimator.ofFloat(0,1f); 就是将一个float值 从0f变到1f

setRepeatCount设置重复次数

setRepeatMode设置重复模式

setInterpolator设置插值器

Interpolator(插值器)系统提供了很多插值器:先加速在减速、加速、匀速、周期运动、先回退再加速、最后弹一下等等。如果不够用可以自定义。

在监听里面能取到当前的值,然后通过invalidateSelf();刷新重绘

image.png
image.png

通过这个变化的值,去改变鱼头的角度,这能实现鱼的摆动(比如鱼头摆动5度,节肢1摆动10度,节肢2摆动20度)这样不同的幅度就让鱼动起来。

鱼尾是通过改变三角的大小来实现的,幅度规律应该跟节肢2一样。

鱼尾是上节(节肢1)带动(节肢2)来运动的,而且是周期规律性的运动

说到周期性运动,又很平滑。sin、cos刚好是这样的

image.png
image.png

所以可以用sin代替0~1f的动画,这样更加平滑。cos刚好比sin多一个象限,那么节肢2刚好可以被节肢1带着。

image.png
image.png
image.png
image.png

鱼游动

鱼整条都是定义在FishDrawable的,用FishRelativeLayout,addView去将ImageView加进来FishDrawable

image.png
image.png
点击水波纹

在onTouchEvent里记录下点击(X,Y),然后根据属性动画去改变圆半径和透明度

image.png
image.png

ObjectAnimator

ObjectAnimator extends ValueAnimator

效果是一样的,将一个属性从 X值改到Y值。可以不用写监听了addListener

入参1.要改变的对象,2.要改变的值(必须实现set方法),3.初始值,4.终点值 -- (或者路径Path)

本质其实是利用反射将 第二个参数的set、get方法里的值给改了。所以一定得实现set、get,不然就报错

image.png
image.png
image.png
image.png
鱼的运动轨迹

鱼的运行轨迹为 3阶贝塞尔曲线,所以关键就是确定4个点

image.png
image.png
已知三点求角度:
607E650E5ABBF23A62A74F4FA76A8F6C.jpg
607E650E5ABBF23A62A74F4FA76A8F6C.jpg

重点就是控制点2的角度

image.png
image.png

求出夹角,还得算出与X轴的夹角也就是

// AB连线与X的夹角的tan值 - OB与x轴的夹角的tan值 float direction = (A.y - B.y) / (A.x - B.x) - (O.y - B.y) / (O.x - B.x);
image.png
image.png
完整各个点:
image.png
image.png

最后游动:

path.cubicTo()三阶贝塞尔曲线公式

通过ObjectAnimator属性动画改变ImageView的xy坐标。

通过fishDrawable.setFrequence(3f) 让鱼在游动的时候运动的更快
image.png
image.png

鱼头的朝向,转过来

鱼头的方向 = 运动轨迹的切线的方向,这样就能平滑的转过来了。

通过取到曲线执行的百分比得到

pathMeasure.getPosTan()

tanα值,然后转换成角度

C128ECB08FEC80F6A8178C683EB630A3.jpg
C128ECB08FEC80F6A8178C683EB630A3.jpg
image.png
image.png

完成

视频:价值100w+Android项目实战大全:灵动的锦鲤

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 画一条鱼
  • 鱼原地摆动
    • ValueAnimator
    • 鱼游动
      • 点击水波纹
        • 鱼的运动轨迹
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档