Android 4+ html5画布不重绘

Posted

技术标签:

【中文标题】Android 4+ html5画布不重绘【英文标题】:Android 4+ html5 canvas not redrawing 【发布时间】:2012-09-30 01:27:09 【问题描述】:

我目前正在使用 phonegap 开发一个 android 应用程序。我有一个 html5 画布,我在上面绘制和动画对象。它在 android 2.3 上运行良好,但在 android 4+ 上它不会重绘画布。我尝试将 kinetic.js 和 easel.js/tween.js 用于我的动画,并且这两个库都出现了不清除画布的问题。我在画布上显示和隐藏 div 时取得了一些成功,但它并不总是有效。我只能假设这是一个 android 4+ 特定的错误或某种类型的功能,以增强 html5 画布性能。

有谁知道是否有一些我可以更改的设置或我可以在 android 4 或 javascript 中调用的方法,这将允许我在动画期间强制重绘我的 html5 画布?

还应注意,动画似乎可以在 4.1 google api 模拟器中使用 easel.js/tween.js(画布清除并重绘),但不适用于运行 4.1.1 的手机。

我对正在发生的事情做了一些进一步的研究。从本质上讲,动画一开始的形状似乎留下了一个工件,而 clearRect 并没有清除它。我有一个大圆圈,我正在缩小到一个小圆圈。动画仍然发生,但大圆圈不受在画布上调用 clearRect 的影响。

【问题讨论】:

所以我想出了一个解决办法。我仍然不知道根本原因或为什么它只发生在 Android 4+ 中。如果我在第一次绘制到画布之前先设置一个 setTimeout。它不再留下文物。 【参考方案1】:

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

之后,我可以在画布上绘制任何东西,并且它在 Android 中表现正常。 (参见下面的示例。在没有背景的情况下,对象在第一次拖动时被复制。要对其进行测试,只需将背景的不透明度设置为 0)。

一个警告:根据我目前的经验,任何给定层中的第一个对象都会发生这种情况。所以我必须调整舞台中的每一层。根据您的应用程序,它可能会或可能不会比在代码中添加时间延迟更好。

这似乎是从 Android 4.1.x 开始的 Android 错误它不会在 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>

【讨论】:

【参考方案2】:

我今天在 Android 4.1.1 上遇到了同样的问题,只是我的问题更令人讨厌。我尝试了其他答案中建议的setTimeout 和“绘制虚拟对象”解决方法,但问题仍然存在。经过更多的尝试和错误,我发现如果我在前几帧(前两帧对我来说足够)绘制虚拟对象,之后可以成功清除画布。

另一个相关问题是,如果我在画布顶部显示一个弹出框,然后将其关闭,画布清除错误将再次发生。而这一次画几帧的虚拟对象不再起作用了,对我有用的是先调整画布的大小,然后再绘制几帧的虚拟对象。

显然,这些都是丑陋的解决方法,但可能对遇到相同问题的其他人有用。

【讨论】:

哇,感谢您发布此信息。在我的情况下,我正在为图像制作动画,并且在动画运行几帧后设置图像可以防止“重影”问题。【参考方案3】:
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);
    ;
);

像魅力一样工作

【讨论】:

以上是关于Android 4+ html5画布不重绘的主要内容,如果未能解决你的问题,请参考以下文章

如何使 HTML5 画布适合动态父/弹性框容器

通过 DLL 将子窗口添加到 Metatrader4 的图表 - 闪烁(不重绘)

UICollectionview 不重绘渐变按钮

UICollectionView 不重绘

图像设置为零时UIImageView不重绘

UIView 不重绘,但元素错位