我的应用程序使用支持包在2.2以上实现Fragment
s。
我有一个View
子类(我们称之为ZoomableView
),它使用ScaleGestureDetector
来检测收缩缩放事件。这是以熟悉的方式完成的;也就是说,在onTouchEvent()
中,使用MotionEvent
将mScaleDetector.onTouchEvent(event)
传递给检测器。aSimpleOnScaleGestureListener
用于接收缩放事件。
这个类始终显示为ZoomableView
中的唯一View
(我们称之为Fragment
)。它在应用程序中有两个用例。在一个用例中,布局只包含ZoomableFragment
,其中包含ZoomableFragment
。在第二个用例中,ZoomableView
将与另一个片段一起显示。另一个ZoomableFragment
恰好包含一个Fragment
,但是MapView
的使用与问题无关(如果第二个MapView
只包含一个普通的Fragment
,问题仍然会发生)。
实际的问题是,当在预冻豆设备(特别是Froyo手机)上测试时,当使用显示双胞胎布局的View
时,Activity
的Fragment
ZoomableFragment
不起作用。当我说“不工作”时,我可以在调试器中看到它处理ZoomableView
s,但是没有调用ScaleGestureDetector
中的任何方法。但是,当使用仅包含MotionEvent
的SimpleOnScaleGestureListener
时,缩放检测确实有效。如果我在我的jellybean设备上尝试这个应用程序,twin-Activity
的情况下工作得非常好;也就是说,会收到缩放手势。
我四处搜索,唯一能找到的问题是人们在哪里实现了ZoomableFragment
并通过从Fragment
返回false来阻止它工作。这不是我的问题。
总之,当在froyo(android 2.2)上的多支持OnScaleGestureListener
布局上的onScaleBegin()
中使用时,aScaleGestureDetector
不会调用它的侦听器,我假设最多包括ic。但是如果屏幕上只有View
一个,那么检测器工作正常。此外,问题不存在于任何我的4.1 +豆豆设备。
编辑1在我的双片段布局中,Fragment
始终放置在右侧或底部,具体取决于方向。我刚刚做的一个有趣的观察是,如果我翻转布局,使得Fragment
在纵向上位于顶部(而不是较低的片段),或者在横向上位于左侧,那么比例检测器工作!因此,我怀疑这与使用片段时ZoomableFragment
ZoomableFragment
/MotionEvent
方法的结果之间的关系有关。但是当我像这样翻转布局时,收缩缩放对相邻的getRawX()
getX()
不起作用!总之,在froyo上,似乎MapView
只对aFragment
中包含的aScaleGestureDetector
起作用,aView
在屏幕的0,0处有一个角。
编辑2在检查grepcode上Fragment
的源代码后,我自己用一个简单的解决方案回答了这个问题。因为即使是在ics使用ScaleGestureDetector
/getRawX()
的情况下,我也更新了这个问题来说明ics受到的影响(我相信),而不是像我最初想的那样仅仅是froyo。
编辑3我做了一个简单的测试,完全消除了与getRawY()
s或我的应用程序中的其他任何东西有关的任何东西。我以简单的googleFragment
为例,简单地修改了布局,这样大部分屏幕都被一个MapView
(权重为0.9)占据,一个很小的TextView
位于底部,权重仅为0.1。在我的Froyo设备上,它将不再收缩变焦。在我的JB设备上,是的。所以看起来我并没有发疯,我遇到了一个关于ics和下面的MapView
的问题(我想-当然是froyo,无论如何),答案给出了一个解决方案。
最佳答案
通过检查grepcode上的ScaleGestureDetector
源代码,我发现ScaleGestureDetector
的jellybean版本没有使用getRawX()
的getRawY()
和MotionEvent
方法。但是,早期版本(froyo、ics等)确实使用了getRawX()
和getRawY()
来计算坡度。这就是问题所在,因为这意味着如果目标View
的左上角不在0,0附近,标度检测器将无法工作。
我让ScaleGestureDetector
来处理我的自定义ZoomView
,即使它被放在右侧或底部,只要在onTouchEvent()
中这样做:
event.setLocation(event.getRawX(), event.getRawY());
mScaleDetector.onTouchEvent(event);
这会导致调整
MotionEvent
的内部偏移变量,使得getX/Y
和getRawX/Y
方法现在返回完全相同的值。这样可以防止坡度计算失败。当然,scale detector与相对值一起工作,因此与x/y的绝对值无关。如果您有更多依赖于绝对值的代码,可以在执行以下操作后执行我所做的恢复操作: float originalY = event.getY();
float originalX = event.getX();
event.setLocation(event.getRawX(), event.getRawY());
mScaleDetector.onTouchEvent(event);
event.setLocation(originalX, originalY);
此外,如果我想将包含
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);
}
现在,我的
MapView
也会适当收缩刻度,不管它的Fragment
放在哪里。(顺便说一下,这个问题完全不是,但是如果有人想知道的话,我使用stackoverflow上给出的MapView
解决方案成功地将aFragment
放入aLocalActivityManager
中)。编辑:事实上,有些东西不是100%正确的:地图没有围绕捏手势的中心缩放。我认为这与getTop()
中没有补偿操作栏/通知栏高度有关。关于android - ScaleGestureDetector不适用于ICS及以下版本的Fragment或ViewGroup布局内的View,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13791904/