手机Android HTML5 硬件加速-画布

4
我遇到了一个奇怪的问题。当我启用硬件加速时,如果我在画布元素上绘制任何内容,那么画布上绘制的任何内容都会重新绘制到页面顶部。
如果关闭硬件加速,则不会出现此问题。
我只在Android 4.1.1上进行了个人测试,但我以前曾注意到我们的一个用户在一段时间之前遇到了这个问题,但我无法复制(他们至少使用的是Android 3+)。
我无法准确地抓取屏幕截图(不太确定如何在Android上做到这一点),但我将尝试分解该过程。
启用硬件加速:
1. 用户填写常规详细信息。 2. 用户滚动到页面底部,在画布元素上绘制签名。 3. 如果用户忘记了页面顶部的某些内容并滚动到页面顶部 4. 出现视觉错误,他们绘制的签名出现在页面顶部
然而,如果没有硬件加速,则不会发生第4步。我需要对HTML5 Canvas执行什么操作?
我不确定需要传递哪些信息-似乎在三星、HTC和Google Nexus手机/平板电脑上都会出现这个问题,因此这是一个一致的错误。
我尝试搜索,但我总是得到游戏开发线程或类似的内容。
我真的很想启用硬件加速,这是唯一出现问题的地方-性能提升非常惊人。

可能不会有太大帮助,但使用硬件加速时,表单输入有时也会表现出异常行为 = 打入的文本出现在屏幕顶部,输入框也滚动出视野。该问题仅在页面大于屏幕时发生。我的想法是,在开始绘制签名时,将页面高度固定为屏幕高度。也许这能有所帮助。 - frequent
不幸的是,这些页面非常动态(并存在于PhoneGap空间中),因为它是服务的一部分。 - DdD
另外要提到的是,我设计了一个在不可滚动页面上使用画布的部分(仅适用于平板电脑)。同样的问题也出现了(该页面上的画布距离页面顶部约40像素,它将在相同位置重新绘制)。 - DdD
我至少有一个线索 - 硬件加速。它将画布转换为“surface view”。我能以任何方式使其重新绘制吗? - DdD
我可以确认,在我的Galaxy Nexus上仍然存在该错误,现在运行的是Android 4.3。这个问题在Android 4.2.2中也存在,而这个手机之前就是运行这个版本的。 - trejder
6个回答

8
在Android 4.1.1版本中出现了HTML5画布重复的问题,而在最新的4.2版本中仍未得到解决。
解决方法是,canvas的所有父级HTML元素都不能设置overflow:hidden或overflow:scroll。

2
我可以确认,在我的Galaxy Nexus上,配备(现在)Android 4.3,该错误仍然存在。它(自然而然地)也存在于此手机之前的Android 4.2.2中。这个错误没有被修复这么多个Android版本,有点奇怪。我们能否确认已向Android的开发团队报告了这个问题? - trejder
3
谢谢 - 这个解决了我的问题,我使用这段代码实施了一个快速修复:$(".canvasElement").parents("*").css("overflow", "visible"); - SammyBlackBaron
如果您正在使用Jquery mobile的修复程序 $(".canvasElement").parents("*").css("overflow", "visible");,请不要忘记在pageshow事件中调用它,否则它将无法正常工作。例如:$('[data-role="page"]').bind('pageshow', function() { $(".canvasElement").parents("*").css("overflow", "visible"); }); - leenix
@SammyBlackBaron 这些评论似乎是唯一正确的解决方法(除了完全禁用硬件加速)。如果画布的任何父级具有溢出隐藏,则GPU将将画布的部分复制到错误的位置。不幸的是,jQuery Mobile有一个讨厌的习惯,即使页面上没有溢出,也会在页面元素右侧添加额外的20像素左右。使用JQM页面使overflow-x可见允许页面向右滚动,从而在侧面暴露出空白条。因此,几乎任何GPU + Canvas + JQM的组合都是有问题的。 - joshstrike
有人知道这影响哪些版本吗?它在4.4中修复了吗?我似乎找不到官方的错误报告? - Deej

2

好的,我想到了最简单粗暴的解决方案。在我的 onTouchEnd 事件触发后,我必须执行以下操作:

1. Append changes to the canvas. It'll double-draw
2. Create a clone of the canvas
3. remove the canvas, re-add it
4. Copy the data from the clone over

然后这个错误就消失了... 真是荒唐。

我必须让它工作,但在去除硬件加速后,我注意到jQM的感觉非常笨重。


1
@frequent 我感觉做这个很不好...这太野蛮了。 - DdD
啊,安卓有时感觉像IE6一样...你也可以将你的hack发布为一个问题在这里 - frequent
你说的“从克隆中复制数据”是什么意思?你指的是哪些数据? - Greg Bala
在克隆画布并创建新画布后,确保完全复制旧画布数据到新画布上。 - DdD
2
@DimitriAdamou 那些在4.1.1和4.3之间的微小错误都没有修复的人(三个常规系统更新,四个?)应该感到不舒服!但你不用,因为你提供了一个hacky但仍然是解决他们无能的方法... - trejder

2
我有同样的问题。在我的情况下似乎是由于jquery mobile css引起的。
再详细地说一下guya所说的,进入jquery.mobile.structure.css文件并更改此行:
.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }

.ui-content { border-width: 0; overflow: visible; padding: 15px; }
删除overflow-x:hidden属性即可解决问题。 来源:Github / thomasjbradley / signature-pad / Issues 编辑:奇怪的是,我注意到当画布宽度为256像素或更小时,问题不会发生。

不,即使你没有使用jQuery Mobile,同样的问题仍然存在。我在我的PhoneGap应用程序中(使用“普通”的jQuery)和一个简单的基于HTML的应用程序中遇到了这个问题,该应用程序没有使用任何框架。 - trejder
“奇怪的是,我注意到当画布宽度小于或等于256像素时,问题并没有发生。”因为在256像素以下,Chrome不会为画布启用硬件加速。这进一步证实了这是一个硬件加速的问题。 - John Weisz

1

对于任何感兴趣的人,Android 5 的表现非常出色,画布速度大大提高。


0

我正在使用分段显示库,它也受到这个问题的影响。在与库的作者进行长时间讨论后,他提出了一个快速解决方法。他告诉我添加这两行代码:

context.fillStyle = '#fff';
context.fillRect(0, 0, display.width, display.height);

就在这行代码之后:

// clear canvas
context.clearRect(0, 0, display.width, display.height);

方案已经测试并且运行得非常好。

通过对给定代码的快速分析,我认为一个透明的(clearRect)画布导致了这些问题,并将其更改为不透明的(fillRect)可以修复该错误。


0

我已经修复了创建视图时的问题:

if (Build.VERSION.SDK_INT >= 16) {
  try {
    Method method = root.getClass().getMethod("setLayerType", int.class, Paint.class);
    method.invoke(root, 0x01/* View.LAYER_TYPE_SOFTWARE */, null);
    Log.d(TAG, "hardware accelaration disabled");
  } catch ...
}

1
但这会移除硬件加速,这正是我不想发生的。 - DdD

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