18 年末作 Readhub APP 时就加入了这个返回动画效果。一直到如今,才有时间来简单总结和封装一下。 git
不知道这个返回手势动画究竟是 MIUI 仍是「即刻」APP 独创,由于我那会儿还没用上 MIUI 全面屏。不过 MIUI 全面屏那个返回手势相对简单,固定位置。从这个效果上看,我以为是 MIUI 先有这个效果,而后 「即刻」APP 优化丰富了一下。固然,可能还有另一种状况,这是早就有的效果图,只是在目前,我已知有使用的就上面两个场景。程序员
总结起来很简单,就是一个「贝塞尔曲线」的绘制,再外加一个箭头绘制。箭头什么的的绘制在以前的仓库中已经练习过不少。此次着重说说这个特殊图形须要怎么绘制。github
对于贝塞尔曲线绘制,以前玩过两阶、三阶的。第一次看到这个效果,以为贝塞尔曲能实现,可是这是几阶的,高阶的怎么玩,那就是从头开始。api
在通过一番把玩探索后,最终肯定这就是五阶的贝塞尔曲线, Android
彷佛默认没有高阶对应的 api。缓存
private fun calculateY(i: Int, j: Int, t: Float): Float {
return if (i == 1) {
(1 - t) * controlPoints[j].y + t * controlPoints[j + 1].y
} else (1 - t) * calculateY(i - 1, j, t) + t * calculateY(i - 1, j + 1, t)
}
复制代码
controlPoints 对应的就是那个五个控制点的集合。函数
addControlPoint(0, 0f, yResult - maxPeakValue * 1.5f)
addControlPoint(1, 0f, yResult - maxPeakValue * 1.5f * GOLDEN_RATIO)
addControlPoint(2, min, yResult)
addControlPoint(3, 0f, yResult + maxPeakValue * 1.5f * GOLDEN_RATIO)
addControlPoint(4, 0f, yResult + maxPeakValue * 1.5f)
复制代码
接着就是控制是否拦截事件,我如今是作成 Helper 这种工具类型,和对应的 ViewGroup
是解耦的,其实就是 ViewDragHelper
的一个简单实现。工具
对了,最后考虑下来,实现了左右两边的滑动效果。至于上下,我以为这种场景不大,就懒得去作了。post
具体代码细节就不贴了,源码也没多少,这里讲遇到的一些细节问题或者写出来的 bug优化
这里其实就是一个前后问题,一开始是同步执行 invalidate()
和 onBackReleased()
。后来使用 Runnable
+ postDalay()
来延迟 onBackReleased()
执行。动画
这里后面排查出来是我添加控制点,for 循环时角标是[0,length-1],最后一个没有添加计算到,因此计算出来的控制点就少了一个。最终效果就是绘制出来的图形 x 轴没有彻底对称。误差就在 1px 左右。 最后的效果就是总感受下方有一跟白线。
for 循环处理好以后,发现右边绘制出来仍是会有这个状况,具体缘由不清楚,由于单看数据层面,它确定是贴边的。最后很讨巧,使用到 translate()
将 Canvas
平移一个像素规避掉,这简直是程序员的小巧思,哈哈 🐶。
由于是用公式算的控制点,因此每一次绘制,其实简单理解就是讲一个一个点链接成一条曲线的。那么问题就是,点多,曲线固然最逼真,可是单位时间处理的数据量就上去了。 点少,可能你看到就是折线图了。 最后均衡在 50 个控制点,点与点之间的比例就是 2% 。在绘制等方法中确定不能频繁建立对象,因此这 50 个点须要复用。
lovejjfg/SwipeBack 现已同步 jcenter 。 详情请移步 README.md