2

我的应用程序使用支持包Fragment在 2.2 以上实现 s。

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

此类ZoomableView始终显示为 a 中的唯一ViewFragment我们称之为它ZoomableFragment)。在应用程序中有两个用例。在一个用例中,布局仅包含ZoomableFragment,包含ZoomableView. 在第二个用例中,ZoomableFragment将显示在另一个 Fragment 旁边。另一个Fragment恰好是容纳 a MapView,但使用MapView与问题无关(如果第二个Fragment只包含一个普通的 ,问题仍然存在View)。

实际问题是,在 Jellybean 之前的设备(特别是 Froyo 手机)上进行测试时,当使用Activity显示双Fragment布局的 ' 时,ZoomableFragment'ZoomableView ScaleGestureDetector不起作用。当我说“不起作用”时,我可以在调试器中看到它处理MotionEvents,但没有SimpleOnScaleGestureListener调用 s 中的任何方法。但是,当使用Activity包含的 时,比例检测确实有效。如果我在我的 JellyBean 设备上试用该应用程序,双胞胎情况绝对可以正常工作;即接收到缩放手势。ZoomableFragmentFragment

我四处搜索,我能找到的唯一问题是人们在哪里实施OnScaleGestureListener并通过从onScaleBegin(). 这不是我的问题。

因此,总而言之,当在 Froyo(Android 2.2)上的多支持布局上ScaleGestureDetector使用时,a 不会调用它的侦听器,我假设包括 ICS。但是,如果这是屏幕上唯一的一个,则检测器工作正常。此外,在我的 4.1+ Jellybean 设备上不存在任何问题。ViewFragmentFragment

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

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

编辑 3我做了一个简单的测试,以完全消除与Fragments 或我的应用程序中的任何其他内容有关的任何内容。我采用了简单的 GoogleMapView示例项目并简单地更改了布局,以便屏幕的大部分被一个(重量 0.9)占据,而底部的TextView一个微小的重量仅为 0.1。MapView在我的 Froyo 设备上,它不会再捏缩放。在我的 JB 设备上,确实如此。所以看来我不会发疯,我在 ICS 及以下(我认为 - 当然是 Froyo,无论如何)上遇到了问题,GestureScaleDetector答案给出了解决方案。

4

1 回答 1

3

通过检查 grepcode 上的源代码,ScaleGestureDetector我看到 Jellybean 版本ScaleGestureDetector不使用. 但是,早期版本(Froyo、ICS 等)确实使用并用于 slop 计算。这就是问题所在,因为这意味着如果目标的左上角不在 0,0 附近,比例检测器将无法工作。getRawX()getRawY()MotionEventgetRawX()getRawY()View

ScaleGestureDetector可以在我的 custom 上工作ZoomView,即使它被放置在右侧或底部,只需在以下范围内执行此操作onTouchEvent()

event.setLocation(event.getRawX(), event.getRawY());    
mScaleDetector.onTouchEvent(event);

这会导致调整MotionEvent' 的内部偏移变量,以使getX/YgetRawX/Y方法现在返回完全相同的值。这可以防止 slop 计算失败。比例检测器当然适用于相对值,因此 X / Y 的绝对值无关紧要。如果您有更多依赖于绝对值的代码,您可以按照我所做的操作来恢复它们:

    float originalY = event.getY();
    float originalX = event.getX();     
    event.setLocation(event.getRawX(), event.getRawY());
    mScaleDetector.onTouchEvent(event);
    event.setLocation(originalX, originalY);

此外,如果我想将Fragment包含 a 的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);
}

现在,我MapView也会正确地捏秤,无论它Fragment放在哪里。(顺便说一句 - 这个问题完全 OT,但如果有人想知道,我将 aMapView放入Fragment成功使用LocalActivityManagerStackOverflow 上给出的解决方案中)。编辑:实际上,有些事情不是 100% 正确的:地图不会围绕捏合手势的中心进行缩放。我认为这与在getTop().

于 2012-12-10T19:23:58.300 回答