pinch zoom是移动应用中非常实用的手势,尤其用于图片浏览。
遗憾的是sencha touch2仍然没有提供现成的官方控件。
人肉了下,找到以下资源:
1.https://market.sencha.com/extensions/pinch-zoom-image
测试了下这个plug-in,存在明显的性能问题,缩放和平移均存在响应迟滞。
2.https://github.com/SunboX/ST2_ImageViewer
有关此控件的讨论,参见这篇帖子:
http://www.sencha.com/forum/showthread.php?197903-Pinch-Image-with-carousel-and-working-fine/page6
此控件响应流畅,但存在一个明显的不足,就是当pinchEnd时,总是会出现画面闪烁。
认真读了相关代码,line254
onImagePinchEnd : function(ev) { var me = this; // set new translation if (me.scale == me.baseScale) { // move to center me.setTranslation(me.translateBaseX, me.translateBaseY); } else { //Resize to init size like ios if (me.scale < me.baseScale && me.getResizeOnLoad()) { me.resetZoom(); return; } // calculate rescaled origin me.originReScaledImgX = me.originScaledImgX * (me.scale / me.startScale); me.originReScaledImgY = me.originScaledImgY * (me.scale / me.startScale); // maintain zoom position me.setTranslation(me.originViewportX - me.originReScaledImgX, me.originViewportY - me.originReScaledImgY); } // reset origin and update transform with new translation me.setOrigin(0, 0); me.applyTransform(); // adjust scroll container me.adjustScroller(); },
分析结论如下:
pinch end结束时出现闪烁,是由于直接将transform缩放之后的图片,由改变宽高、然后scrollto局部。
这中间改变宽高,再scrollto,始终对一个图片操作,而这个过程,图片经历了位置、尺寸的变化。
改进的思路如下:
要避免闪烁,必须做到,在图片的整个改变中,显示在屏幕前的始终是同样的画面,那么改变只能在后面发生,可以利用background-image作为切换的遮羞布。
具体步骤是:
- 通过设置底图,先将底图变化为与当前局部一致;
- 隐藏图片,显示底图,由于两者一致,不会出现闪烁;
- 变化图片坐标,scrollto局部;
- 显示图片;
- 隐藏底图;
- 整个过程最前面的局部图始终保持不变,因此去掉闪烁。
改进后的代码:
onImagePinchEnd : function(ev) { var me = this; // set new translation if (me.scale == me.baseScale) { // move to center me.setTranslation(me.translateBaseX, me.translateBaseY); } else { //Resize to init size like ios if (me.scale < me.baseScale && me.getResizeOnLoad()) { me.resetZoom(); return; } // calculate rescaled origin me.originReScaledImgX = me.originScaledImgX * (me.scale / me.startScale); me.originReScaledImgY = me.originScaledImgY * (me.scale / me.startScale); // maintain zoom position me.setTranslation(me.originViewportX - me.originReScaledImgX, me.originViewportY - me.originReScaledImgY); } //c4w var scale=me.scale; var bw = me.imgWidth * scale; var bh = me.imgHeight * scale; var bs=bw+'px '+bh+'px'; var x = 0; if (me.scrollX!=0) { x = me.scrollX; }else{ x = me.translateX; } var y = 0; if (me.scrollY!=0) { y = me.scrollY; }else{ y = me.translateY; } var px=x+'px '+y+'px'; me.element.setStyle({ backgroundImage : 'url(' + me.getImageSrc() + ')', backgroundAttachment: 'fixed', backgroundPosition : px, backgroundSize: bs, backgroundRepeat : 'no-repeat' }); me.imgEl.dom.style.visibility ='hidden'; //c4w //me.ds=px+"\n"+bs; setTimeout(function() { me.setOrigin(0, 0); me.applyTransform(); // adjust scroll container me.adjustScroller(); me.imgEl.dom.style.visibility ='visible'; me.element.setStyle({ backgroundImage : 'none' }); }, 50); //c4wend },
在iphone4上做了测试,效果令人满意。