为什么在捏缩放手势期间调用setScaleX会导致闪烁



我正在尝试创建一个可缩放的容器,我的目标是API 14+

在我的onScale(我使用ScaleGestureDetector来检测缩放)中,我正在做这样的事情:

public boolean onScale (ScaleGestureDetector detector) {
   float scaleFactor = detector.getScaleFactor();
   setScaleX(getScaleX() * scaleFactor);
   setScaleY(getScaleY() * scaleFactor);
   return true;
};

它可以工作,但缩放不平滑。事实上,它明显在闪烁。

我还尝试了硬件层,认为一旦纹理上传,缩放就会在GPU上进行,因此速度会非常快。但这并没有什么不同——变焦不平滑,有时会奇怪地闪烁。

我做错了什么?

闪烁看起来像是在缩放和未缩放之间来回切换的视图吗?这是由于ScaleGestureDetector在缩放的同一视图中处理运动事件造成的。当您setScaleX()时,它会更改触摸的坐标,从而触发一个新的触摸事件,该事件被解释为反转您刚刚应用的缩放。

将可缩放视图的内容放在单个子FrameLayout中,并在该视图上设置比例。

我在这里发布了一个工作夹缩放布局:https://gist.github.com/anorth/9845602

根据您的问题,方法setScaleXsetScaleY会闪烁,因为它们在"绘制到视图"上下文中执行(setScaleXsetScaleY属于View)。文件显示:

当您想要绘制不需要动态更改且不属于性能密集型游戏的简单图形时,选项"a"绘制到视图是您的最佳选择。例如,如果要在静态应用程序中显示静态图形或预定义动画,则应将图形绘制到视图中。

另一方面,如果按照@g00dy的答案,则将在"绘制画布"上下文中执行(scale()属于Canvas)。文件显示:

当应用程序需要定期重新绘制自身时,选项"b"(绘制到画布上)效果更好。视频游戏等应用程序应该自己绘制到画布上。

捏手势是密集的,因此需要在选项b中执行。。。所以您应该使用@g00dy解决方案或类似的任何方法。

这是引用的文件。

我希望它能帮助你。

我也遇到了同样的问题。任务是:

  • 创建画布(在View或SurfaceView的子类中,无关紧要)
  • 在上面绘制一些图片和图形基元(使用方法drawBitmap()、drawLine()…)
  • 使画布可滚动和缩放

我想,不需要在这里显示所有的类代码。

缩放手势过程中闪烁问题的解决方法非常简单。只需将缩放过程放入onScaleEnd()方法中即可。

private class MyScaleGestureListener implements OnScaleGestureListener
{
    public boolean onScale(ScaleGestureDetector detector)
    {   
        scaleFactor *= detector.getScaleFactor();  // class variable of type float
        if (scaleFactor > 5) scaleFactor = 5;      // some limitations
        if (scaleFactor < 1) scaleFactor = 1;
        return true;
    }
    public boolean onScaleBegin(ScaleGestureDetector detector)
    { return true;}
    public void onScaleEnd(ScaleGestureDetector detector) 
     {
       setScaleX(scaleFactor); setScaleY(scaleFactor); 
       invalidate();     // it seems to me - no effect
     }
} 

在实际设备上测试三星GALAXY S III mini。

最新更新