ScaleGestureDetector不适用于ICS及以下的Fragment或ViewGroup布局中的View

时间:2012-12-09 21:15:33

标签: android android-fragments android-2.2-froyo

我的应用程序使用支持包在2.2版本上实现Fragment

我有一个View子类(我们称之为ZoomableView),它利用ScaleGestureDetector来检测pinch缩放事件。这是以熟悉的方式完成的;也就是说,在onTouchEvent()内,使用MotionEventmScaleDetector.onTouchEvent(event)传递给检测器。 SimpleOnScaleGestureListener用于接收比例事件。

ZoomableView课程始终显示为View中的唯一Fragment(我们称之为ZoomableFragment)。应用程序中有两个用例。在一个用例中,布局仅包含ZoomableFragment,其中包含ZoomableView。在第二个用例中,ZoomableFragment将与另一个片段一起显示。其他Fragment恰好包含MapView,但使用MapView与问题无关(如果第二个Fragment只包含一个View,则问题仍然存在普通的Activity)。

实际问题是,在使用pre-Jellybean设备(特别是Froyo手机)进行测试时,当使用显示双人Fragment布局的ZoomableFragment时,ZoomableView ScaleGestureDetector MotionEvent不起作用。当我说“不起作用”时,我可以在调试器中看到它处理SimpleOnScaleGestureListener,但Activity中没有一个方法被调用。但是,当使用仅包含 ZoomableFragment的{​​{1}}时,比例检测确实有效。如果我在我的JellyBean设备上尝试应用程序,那么双Fragment情况就可以了;也就是说,收到比例手势。

我一直在搜索,我找到的唯一问题是人们已经实施了OnScaleGestureListener并且通过从onScaleBegin()返回false来阻止它工作。这不是我的问题。

总而言之,ScaleGestureDetector在Froyo(Android 2.2)上的多个支持View版面上的Fragment内使用时,{@ 1}}不应调用其监听器假设包括ICS在内。但是,如果Fragment是屏幕上唯一的,则检测器工作正常。此外,我的4.1+ Jellybean设备上不存在任何问题。

编辑1 在我的双片段布局中,ZoomableFragment始终位于右侧或底部,具体取决于方向。我刚才做的一个有趣的观察是,如果我翻转布局使得ZoomableFragment位于纵向(而不是下方片段)的纵向(或者在水平方向的左侧),那么比例探测器工作!因此,我怀疑这与使用Fragments时MotionEvent getRawX() / getX()(和Y类似)方法的结果之间的关系有关。但是当我像这样翻转布局时,捏缩放然后不适用于相邻的MapView Fragment!总而言之,在Froyo上,似乎ScaleGestureDetector仅适用于View中包含的Fragment,该角落位于屏幕的0,0处。

编辑2 我现在用一个简单的解决方案回答了这个问题,我在检查了grepcode上ScaleGestureDetector的来源之后就来了。因为即使ICS的来源使用getRawX() / getRawY(),我也更新了这个问题,直到ICS受到影响(我相信),而不仅仅是我最初想到的Froyo 。

编辑3 我做了一个简单的测试,完全消除了与我的应用程序中的Fragment或其他任何事情有关的事情。我采用了简单的Google MapView示例项目,只是更改了布局,以便大部分屏幕被TextView(权重0.9)占用,而小MapView位于底部重量只有0.1。在我的Froyo设备上,它将不再捏缩放。在我的JB设备上,它确实如此。因此,我似乎并没有疯狂,而且我在ICS及其下方遇到过GestureScaleDetector的问题(我认为 - 无论如何都是Froyo),答案给出了解决方案。

1 个答案:

答案 0 :(得分:3)

通过检查grepcode上的ScaleGestureDetector源代码,我发现ScaleGestureDetector的Jellybean版本没有使用getRawX()的{​​{1}}和getRawY()方法}。但是,早期版本(Froyo,ICS等)使用MotionEventgetRawX()进行斜率计算。这就是问题所在,因为这意味着如果目标getRawY()的左上角没有接近0,0,则比例检测器将无法工作。

我让View处理我的自定义ScaleGestureDetector,即使它被放置在右侧或底部,只需在ZoomView内执行此操作:

onTouchEvent()

这导致调整event.setLocation(event.getRawX(), event.getRawY()); mScaleDetector.onTouchEvent(event); 的内部偏移变量,使MotionEventgetX/Y方法现在返回完全相同的值。这可以防止斜率计算失败。比例检测器当然使用相对值,所以它与X / Y的绝对值无关。如果你有进一步的代码依赖于绝对值,你可以做我做了以后恢复它们:

getRawX/Y

此外,如果我想在底部或右侧放置包含 float originalY = event.getY(); float originalX = event.getX(); event.setLocation(event.getRawX(), event.getRawY()); mScaleDetector.onTouchEvent(event); event.setLocation(originalX, originalY); 的{​​{1}},我仍然在使用Fragment的自定义子类,所以我只是添加了这个:

MapView

现在,无论MapView位于何处,我的public boolean onTouchEvent(MotionEvent event) { // Work around required for ScaleGestureDetector. // Before calling the scale detector, perform a work-around that is needed for earlier APIs (I suspect // ICS and below, judging from inspection of ScaleGestureDetector) to make the MotionEvent give the // same values for getY / getRawY and getX / getRawX. Wildly different values, caused by the View // being nowhere near the screen origin (i.e. the View is on the right or the bottom) means the // detector doesn't work. event.setLocation(event.getRawX() - getLeft(), event.getRawY() - getTop()); return super.onTouchEvent(event); } 都会正确缩放比例。 (顺便说一下 - 对于这个问题完全是OT,但是如果有人想知道,我使用StackOverflow上给出的MapView解决方案成功地将Fragment放入MapView编辑:实际上,某些内容并非100%正确:地图不会缩放捏合手势的中心。我认为这与Fragment中没有得到补偿的ActionBar /通知栏高度有关。