Android MIUI 即刻APP 返回手势及动画 探索

swipe_left.jpeg
swipe_right.jpeg

18 年末作 Readhub APP 时就加入了这个返回动画效果。一直到如今,才有时间来简单总结和封装一下。 git

swipeback.gif

不知道这个返回手势动画究竟是 MIUI 仍是「即刻」APP 独创,由于我那会儿还没用上 MIUI 全面屏。不过 MIUI 全面屏那个返回手势相对简单,固定位置。从这个效果上看,我以为是 MIUI 先有这个效果,而后 「即刻」APP 优化丰富了一下。固然,可能还有另一种状况,这是早就有的效果图,只是在目前,我已知有使用的就上面两个场景。程序员

总结起来很简单,就是一个「贝塞尔曲线」的绘制,再外加一个箭头绘制。箭头什么的的绘制在以前的仓库中已经练习过不少。此次着重说说这个特殊图形须要怎么绘制。github

对于贝塞尔曲线绘制,以前玩过两阶、三阶的。第一次看到这个效果,以为贝塞尔曲能实现,可是这是几阶的,高阶的怎么玩,那就是从头开始。api

在通过一番把玩探索后,最终肯定这就是五阶的贝塞尔曲线, Android 彷佛默认没有高阶对应的 api。缓存

draw
那这怎么办呢?曲线就是函数嘛,确定有公式,网上就搜到公式写法。

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

相关文章
相关标签/搜索