我的应用程序使用支持包在2.2版本上实现Fragment
。
我有一个View
子类(我们称之为ZoomableView
),它利用ScaleGestureDetector
来检测pinch缩放事件。这是以熟悉的方式完成的;也就是说,在onTouchEvent()
内,使用MotionEvent
将mScaleDetector.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),答案给出了解决方案。
答案 0 :(得分:3)
通过检查grepcode上的ScaleGestureDetector
源代码,我发现ScaleGestureDetector
的Jellybean版本没有使用getRawX()
的{{1}}和getRawY()
方法}。但是,早期版本(Froyo,ICS等)做使用MotionEvent
和getRawX()
进行斜率计算。这就是问题所在,因为这意味着如果目标getRawY()
的左上角没有接近0,0,则比例检测器将无法工作。
我让View
处理我的自定义ScaleGestureDetector
,即使它被放置在右侧或底部,只需在ZoomView
内执行此操作:
onTouchEvent()
这导致调整event.setLocation(event.getRawX(), event.getRawY());
mScaleDetector.onTouchEvent(event);
的内部偏移变量,使MotionEvent
和getX/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 /通知栏高度有关。