安卓4以上的html5画布不重绘

6
我正在使用phonegap开发一个Android应用程序。我有一个html5画布,在上面绘制和动画化物体。在Android 2.3上运行良好,但是在Android 4+上它不会重新绘制画布。我尝试使用kinetic.js和easel.js/tween.js来进行动画,但两个库都存在清除画布的问题。有时候在canvas上方显示和隐藏div可以解决此问题,但并非总是有效。我只能认为这是Android 4+特定的错误或某种增强html5画布性能的功能。
有没有人知道是否有一些设置我可以更改或者方法我可以在Android 4或JavaScript中调用,在动画期间强制重绘我的html5画布?
还应该注意到,在4.1 google api模拟器中,easel.js/tween.js的动画似乎可以正常工作(画布清除并重新绘制),但在运行4.1.1的手机上却无法正常工作。
我已经进一步研究了发生的情况。实质上,似乎动画的开始处的形状留下了一个残留物,而clearRect无法清除。我有一个大圆正在缩小成一个小圆。动画仍然发生,但通过在画布上调用clearRect对大圆没有任何影响。

1
所以我找到了一个解决方法。我仍然不知道根本原因或为什么它只发生在Android 4+上。如果我在第一次绘制到画布之前设置一个一秒的setTimeout,它就不会再留下痕迹了。 - Dan Fischer
3个回答

7
我也没有解决根本问题的方法,但我想出了另一个不完美的解决方法,不会给您的代码增加延迟。首先在画布上绘制一个虚拟对象,然后再绘制动画对象(或可拖动对象,因为它也会发生拖动)。似乎第一个绘制的对象是持久的(即无法正确清除)。使用KineticJs时,我执行以下操作...1)创建舞台,2)绘制一个对象(如作为背景的舞台大小的矩形。请注意,对象不能是透明的),3)将图层添加到舞台中,4)运行layer.draw()。

之后,我可以在画布上绘制任何内容,并且在Android上正常工作。(请参见下面的示例。如果没有背景,则在第一次拖动时对象会重复。要测试它,只需将背景的不透明度设置为0)。

需要注意的是:根据我的经验,这种情况仅发生在每个给定图层中的第一个对象上。因此,我必须调整舞台中的每个图层。根据您的应用程序,它可能比向代码添加时间延迟更好,也可能不是。

这似乎是一个Android的bug,从Android 4.1.x开始出现。在4.0.x中不会发生。而且,在本周发布的最新版本4.1.2中也没有修复此问题。类似的问题与CSS中overflow-x属性的设置有关(参见http://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=35474)。
<script>
  window.onload = function() {
    var stage = new Kinetic.Stage({
      container: "container",
      width: 578,
      height: 200
    });

    var boxLayer = new Kinetic.Layer();
    stage.add(boxLayer);
        var background = new Kinetic.Rect({
          x: rectX,
          y: rectY,
          width: 578,
          height: 200,
          fill: "white",
          stroke: "white",
          strokeWidth: 4,
          draggable: false
        });
    boxLayer.add(background)
    boxLayer.draw();


    var rectX = stage.getWidth() / 2 - 50;
    var rectY = stage.getHeight() / 2 - 25;

    var box = new Kinetic.Rect({
      x: rectX,
      y: rectY,
      width: 100,
      height: 50,
      fill: "#00D2FF",
      stroke: "black",
      strokeWidth: 4,
      draggable: true,
      opacity: 1.0            
    });

    boxLayer.add(box);
    boxLayer.draw();


  };

</script>

1
function drawImage(imageObj) {
    var stage = new Kinetic.Stage({
        container: "container",
        width: wW,
        height: wH
    }),
    timer = null,
    dummys = 1,
    layer = new Kinetic.Layer();

    timer = setInterval( function() {
        if( dummys >= 2 ) {
            clearInterval(timer);
            layer.clear();
            var darthVaderImg = new Kinetic.Image({
                image: imageObj,
                x: stage.getWidth() / 2 - 200 / 2,
                y: stage.getHeight() / 2 - 137 / 2,
                draggable: true
            });
            layer.add(darthVaderImg);
            stage.add(layer);   
        }else{
            var background = new Kinetic.Rect({
              x: 0,
              y: 0,
              width: wW,
              height: wH,
              fill: "white",
              draggable: false
            });
            layer.add(background)
            layer.draw();
            dummys++;
        }
    }, 10 );

}

var wH = window.innerHeight,
    wW = window.innerWidth,
    mCanvas = document.getElementById('container'),
    imageObj = new Image();

$(document).ready(function(){
    mCanvas.style.width = wW;
    mCanvas.style.height = wH;
    imageObj.src = 'img/darth-vader.jpg';
    imageObj.onload = function() {
        drawImage(this);
    };
});

运行得非常好


1
今天在Android 4.1.1上遇到了同样的问题,只是我的问题更加棘手。我尝试了其他答案中建议的setTimeout和“绘制虚拟对象”解决方法,但问题仍然存在。经过更多的尝试和错误,我发现如果我在前几帧(对我来说前两帧就足够了)绘制虚拟对象,之后就可以成功清除画布。
另一个相关的问题是,如果我在画布上方显示一个弹出窗口,然后将其关闭,画布清除错误将再次发生。这一次,仅仅绘制几帧虚拟对象已经不再起作用了,对我有用的是先调整画布大小,然后再绘制几帧虚拟对象。
显然,这些都是丑陋的解决方法,但可能对其他遇到相同问题的人有用。

哇,感谢您发布这个。在我的情况下,我正在制作动画图像,并在动画运行了几帧之后设置图像,以避免出现“幽灵”问题。 - Booker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接