效果预览
功能阐明
- 使用Canvas绘制元素移动动效,极致高效;
- 支持恣意方向元素漂移(出发点、止境恣意);
- 支持修改元素图标及其大小(单位dp);
- 支持修改动效连续时间及动画结束时回调;
- 支持修改元素飘动个数;
使用方式
allprojects { repositories { maven { url 'https://www.jitpack.io' } ... }}
implementation 'com.gitee.chockqiu:animation-views:1.1'
<com.chockqiu.view.ElementFloatTogetherAnimation android:layout_width="match_parent" android:layout_height="match_parent" />
val p0 = Point().apply { x = (viewStart.left + viewStart.right) / 2 y = (viewStart.top + viewStart.bottom) / 2}val p1 = Point().apply { x = (endView.left + endView.right) / 2 y = (endView.top + endView.bottom) / 2}mElement.startAnimation(p0, p1) { ...}PS: 为了起/止境坐标与预期划一,发起将View放置在跟出发点止境View同一个ViewGroup中,而且动效View的宽高与ViewGroup划一,也就是match_parent(动效内部坐标系是以自身左上角为坐标原点举行绘制的),如不划一须要举行坐标转换。
实现原理
使用二阶贝塞尔曲线控制点决定曲线路径的特性,通过算法天生每一个元素的控制点,实现差别元素通过差别的路径从出发点飘向止境,再加上差别元素移动动画开始的时间差,终极组合实现这么一种效果。
二阶贝塞尔曲线原理图如下:
实现步骤
1)实现二阶贝塞尔曲线数学公式;
具体实现详见quadToFunValue(float t, Point p0, Point p1, Point p2)函数。
2)通过算法天生每个元素的控制点,为了悦目控制点需在出发点与止境地点直线的中垂线上随机分布;
以是终极控制点是一个与中点M(Mx,My)间隔为D的坐标,且它地点的直线是出发点与止境地点直线的中垂线。
如何盘算控制点坐标呢?
起首通过出发点止境地点的直线可以盘算出中垂线的斜率k2:
private double centerk(Point a, Point b) { //已知A(Ax,Ay),B(Bx,By); 中垂线的斜率为: //-1/k=-1/[(By-Ay)/(Bx-Ax)]=-(Bx-Ax)/(By-Ay) if (b.y == a.y) { return 0; } if (b.x == a.x) { return Double.MAX_VALUE; } return -(((b.x - a.x) * 1f / (b.y - a.y)));}已知随机简直定正值D,可以盘算出控制点与坐标中点M(Mx,My)的坐标间隔dx和dy, 数学公式如下:
等式1: dy/dx = k2
等式2: dx*dx + dy*dy = D*D
只要出发点/止境确认, 则k1是一个定值,那么它的中垂线斜率k2也是定值,再加上随机的正值D,颠末转换可得
dx = D*D/(k2*k2+1)
dy = (D*D*k2*k2)/(k2*k2+1)
/** * 斜率k时间隔d对应的dx值 * * @param k 斜率k * @param d 间隔d * @return */private double dx(double k, double d) { if (k == 0) { return 0; } if (k == Double.MAX_VALUE) { return d; } double dx = Math.sqrt((d * d) / (k * k + 1)); if (d < 0) { return -dx; } else { return dx; }}/** * 斜率k时间隔d对应的dy值 * * @param k 斜率k * @param d 间隔d * @return */private double dy(double k, double d) { if (k == 0) { return d; } if (k == Double.MAX_VALUE) { return 0; } double dy = Math.sqrt((d * d) * (k * k) / (k * k + 1)); if (d < 0) { return -dy; } else { return dy; }}在根据出发点(Sx,Sy)、止境(Ex,Ey)的朝向差别,确定dx与dy的符号,大概是-dx,-dy,也大概是dx,-dy等等
终极得到控制点的准确坐标值;
如果本文对你有资助就点个赞支持下吧~~~ |