兴趣部落页面中,为了加强下拉刷新的体验效果,我们用 web 模拟了 ios 下手 Q 下拉刷新时的水滴效果,实现效果如下。
页面开发已经很久,今天写这篇来总结一下吧。
实现原理
这里分为几个部分
实现的关键在于水滴的绘制部分,考虑到尺寸特别小,这里我们使用 canvas 来进行绘制
为什么是 canvas
首先用 CSS3 来做的话会非常麻烦,很多东西不能直接控制,并且涉及到动画,所以基本不用考虑,SVG 的话也是不错的选择,就是控制也不是很方便,Canvas 就性能和控制性上都比较高,所以最终选择了 Canvas 来做关键帧的绘制。
水滴的绘制
如果仔细观查水滴是由三部分组成,两个半圆加中间连接线,如果两个半圆的端点用直线连起来的话,看起来过渡会很生硬,如下所示
所以我们要选择一个好一点的曲线来连接两个半圆。但实际上,水滴的绘制可以是完全用贝塞尔曲线绘制的
鉴于 canvas 使用三次贝塞尔曲线绘制比较复杂一点(其实也还好,三次贝塞尔曲线要求两个控制点,控制点选择坚直就好了,具体没有尝试,这可能是一个优化点),所以考虑用二次的贝塞尔曲线来连接两个半圆,所以问题变成是如何选择二次贝塞尔曲线的控制点
二次贝塞尔曲线
二次贝塞尔曲线的 canvas Api 大家可以在网上搜到
JavaScript 语法:
1 |
context.quadraticCurveTo(cpx,cpy,x,y); |
下面有一个动画图更能反映这个曲线的绘制过程
控制点的选择其实也有很多种,这里我选用了两个连接点连线的垂直平分线上的点,如下图所示,两条蓝线是两条连线的垂直平分线,在这上面的点,会使弧线过渡很均匀
这样做出来,在图像很小的情况下也很漂亮,只是连接点的不是连续的(左导 !=右导),但还可以接受。
所以按这种方法绘制水滴,用 canvas 这样绘制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
ctx.beginPath(); // 画顶圆 ctx.arc(topRound[0], topRound[1], topR, - Math.PI, 0); // 计算控制点 // 先计算垂分线 // 找出垂分线上 向水滴里面的 一点做控制点 // 使用控制点画贝塞尔曲线到 底部圆连接点 ctx.quadraticCurveTo(point[0], point[1], bottomRound[0] + bottomR, bottomRound[1]); // ...另一侧也是这样画 // 闭合 ctx.closePath(); // 填充 ctx.fill(); //画边 ctx.stroke(); |
其中可能要计算垂直平分线,计算的原理比较简单,先计算出两个连接点 p0, p1 的斜率 k,然后,计算出两点的中点 pm,垂分线方程就是 y - ypm=-1/k * (x - xpm), 然后再取靠中点向里一点的值 x, 计算 y 就可以了,这样控制点坐标就计算出来了
这里要特别说明的是,对于高清屏,canvas 的绘制要用两倍宽高去绘,用 css 把 canvas 缩放回来
其他的一些参数如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
canvas.width = WIDTH; canvas.height = HEIGHT; // 为高清屏缩放 canvas.style.width = ~~ (WIDTH / 2) + "px"; canvas.style.height = ~~ (HEIGHT / 2) + "px"; // 画笔和填充颜色的配置 ctx.fillStyle = "#b1b1b1"; ctx.strokeStyle = "rgb(118,113,108)"; // 为了让效果更好 设置上角的一点点高光 ctx.shadowColor = "#ccc"; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 2; ctx.shadowBlur = 1; // 画笔宽度为1 ctx.lineWidth = 1; |
左为原生,右为 web 实现
更细节的对比
上为原生,下为 web 实
ICON 贴图
中间的 ICON 就没有用 canvas 去画在上面,直接是 DOM 覆盖在 canvas 上
动画的实现
在 IOS 上,因为弹性滚动,某个 DOM 可以被拉下,其 scrollTop 可以为负值(-),我们就跟据被拉下元素的 scrollTop 的负值的大小,依次绘制出此时的水滴即可。
chasel 2017 年 9 月 8 日
能把整个源码分享出来么?
爱奇趣分享网 2015 年 9 月 4 日
不错的站点, 以后一定常来。
jinlong1989 2015 年 7 月 2 日
另外,文章中有些图片貌似没有出来,很想了解一下这块的具体处理,谢谢
jinlong1989 2015 年 7 月 2 日
你好 为什么我在我的 chrome 模拟器下没法看到下拉刷新的效果?
TAT.dorsywang 2015 年 7 月 7 日
用最新的 chrome,选择 iPhone5 或者 iPhone6 试试
jinlong1989 2015 年 7 月 8 日
版本 44.0.2403.61 beta (64-bit) 应该是最新的。用 iPhone5 及 6 都试过。打开的是 http://xiaoqu.qq.com/mobile/barindex.html?_wv=1027&bid=10525&_bid=128&from=share_link#type&from=dongtai&target=hot&from=dongtai&webview=1 这个部落页面。貌似还是不行。
TAT.dorsywang 2015 年 7 月 8 日
看了下 确实如此 我们已经去掉了 web 的,使用了 native 的来做了
jinlong1989 2015 年 7 月 13 日
好的,谢谢