2012-12-09 27 views
1

我的應用程序使用支持包在2.2以上實現Fragment s。ScaleGestureDetector不適用於在ICS上的片段或ViewGroup佈局中查看

我有一個View子類(我們稱之爲ZoomableView),它利用ScaleGestureDetector來檢測縮放縮放事件。這是以熟悉的方式完成的;即在onTouchEvent()內,MotionEvents使用mScaleDetector.onTouchEvent(event)傳遞給檢測器。 A SimpleOnScaleGestureListener用於接收比例事件。

這個ZoomableView類總是在Fragment(我們稱之爲ZoomableFragment)內顯示爲唯一的View。在應用程序中有兩種用例。在一個用例中,佈局僅包含ZoomableFragment,其中包含ZoomableView。在第二個用例中,ZoomableFragment將與另一個片段一起顯示。此其他Fragment恰巧是住房MapView,但MapView的使用與問題無關(如果第二個Fragment只包含普通的View,問題仍然會發生)。

的實際問題是,用Activity,顯示twin- Fragment佈局時的預傑利貝恩設備(具體地,一個升級Froyo電話),上測試時,所述ZoomableFragmentZoomableViewScaleGestureDetector不起作用。當我說'不起作用'時,我可以在調試器中看到它處理MotionEvent,但沒有調用SimpleOnScaleGestureListener中的任何方法。但是,使用Activity時只包含只有,ZoomableFragment,規模檢測確實有效。如果我在我的軟糖設備上嘗試應用程序,雙Fragment情況工作絕對正常;也就是說,接收到比例手勢。

我搜索了四周,唯一的問題是我可以找到的地方是人們實施OnScaleGestureListener,並通過從onScaleBegin()返回false來阻止它工作。這不是我的問題。

因此,在總結,一個ScaleGestureDetector不調用它的監聽器當上升級Froyo(Android 2.2的)多支持Fragment佈局View內使用時,它應該做的,我以爲直至幷包括ICS。但是如果Fragment是屏幕上唯一的一個,檢測器工作正常。此外,這個問題在我的4.1+ Jellybean設備上不存在。

編輯1在我的雙片段佈局,ZoomableFragment總是被放置在右側或底部取決於方向。我剛剛做出的一個有趣的觀察是,如果我翻轉佈局,使得ZoomableFragment在縱向方向上位於頂部(而不是下面的片段),或者在水平方向位於左側,那麼比例檢測器就可以工作!因此,我懷疑這是在使用碎片時與MotionEventgetRawX()/getX()(以及類似的Y)方法的結果之間的關係。但是當我像這樣翻轉佈局時,捏縮放然後對相鄰的MapViewFragment不起作用!因此,總而言之,在Froyo上,似乎ScaleGestureDetector僅適用於Fragment中包含的View,該屏幕的角落爲0,0。

EDIT 2現在我已經回答了這個問題,我有一個簡單的解決方案,我就grepcode檢查源ScaleGestureDetector後前來。因爲即使ICS使用的是getRawX()/getRawY(),我已經更新了這個問題,以說明ICS受到影響(我相信),而不僅僅是我首先想到的Froyo。

編輯3我已經做了一個簡單的測試,以完全消除與Fragment s或我的應用程序中的其他任何事情。我採取了簡單的Google MapView示例項目,並簡單地更改了佈局,以便屏幕的大部分被TextView(權重0.9)佔據,而小MapView位於底部,權重僅爲0.1。在我的Froyo設備上,它不會再縮放變焦。在我的JB設備上,它確實如此。所以看起來我並不瘋狂,而且我在ICS和以下(我認爲 - 無論如何Froyo都會遇到)GestureScaleDetector的問題,因爲答案可以解決問題。

回答

3

從檢查上grepcode的ScaleGestureDetector源代碼,我看到的ScaleGestureDetector傑利貝恩版本不作的MotionEventgetRawX()getRawY()方法使用。然而,較早的版本(Froyo,ICS等)利用getRawX()getRawY()爲了計算斜坡的目的。這是問題所在,因爲這意味着如果目標View的左上角沒有接近0,0,則比例檢測器將無法工作。

我得到了ScaleGestureDetector通過簡單地這樣做內onTouchEvent()在我的自定義ZoomView工作,即使它被放置在右側或底部,:

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

這導致的MotionEvent的內部偏移調整變量,以使getX/YgetRawX/Y方法現在返回完全相同的值。這可以防止污垢計算失敗。當然,比例檢測器的工作原理與相對值有關,因此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是plac編輯。 (順便說一句 - 對這個問題完全是OT,但如果有人想知道,我使用StackOverflow給出的LocalActivityManager解決方案成功地將MapView放入Fragment)。 編輯:實際上,某些東西並非100%正確:地圖不會縮小夾點手勢的中心。我認爲這與在getTop()中沒有得到補償的ActionBar /通知欄高度有關。