2013-06-30 46 views
6

我想創建一個可縮放的容器,我目標API 14+爲什麼在縮放手勢過程中調用setScaleX會導致閃爍?

在我onScale(我使用的ScaleGestureDetector檢測捏縮放)我做這樣的事情:

public boolean onScale (ScaleGestureDetector detector) { 
    float scaleFactor = detector.getScaleFactor(); 
    setScaleX(getScaleX() * scaleFactor); 
    setScaleY(getScaleY() * scaleFactor); 

    return true; 
}; 

它的工作原理,但變焦不平滑。實際上它明顯地閃爍。

我也試過硬件層,認爲一旦紋理上傳後縮放會發生在GPU上,因此會超快。但它沒有什麼區別 - 變焦不平滑,有時候會變幻莫測。

我在做什麼錯?

+0

我不想發表一個答案,因爲我無法測試解決方案,但你可以,所以採取一個lokk在這裏:http://stackoverflow.com/questions/5790503/can-we-use-尺度手勢檢測器捏捏放大在Android。嘗試後,請返回此處並告訴我們是否解決了問題。看看最後的回覆。 – g00dy

+1

我意識到這個解決方案,但它有嚴重的缺陷 - 它只能縮放畫布的畫布 - 沒有剪輯和觸點被轉換。這就是爲什麼我使用了setScale,它改變了容器中的變換矩陣,並調整了剪輯矩形並適當地轉換了觸摸座標(無需您自己執行矩陣運算) –

+1

您可以分享更多代碼嗎?具體是實際的繪圖例程。你有沒有嘗試過任何分析,看看圖紙在哪裏掙扎?我會考慮在緊縮繪圖循環中最小化(可能爲零)對象分配的數量。我知道這些都是一般的(也許很明顯),但是如果沒有更多的信息,很難多說。 – snowdragon

回答

0

你的問題據,方法setScaleXsetScaleY閃爍,因爲他們的「繪圖視圖」上下文(setScaleXsetScaleY屬於View)內執行。文件說:

選項「一」引到View,是您最佳的選擇,當你想繪製簡單的圖形不需要動態改變,不是性能密集型遊戲的一部分。例如,如果要在靜態應用程序中顯示靜態圖形或預定義動畫,則應將圖形繪製到視圖中。

在另一方面,如果你按照@ g00dy答案,你將在「繪圖畫布」上下文中執行(scale()屬於Canvas)。文檔說:

當您的應用程序需要定期重新繪製自己時,選項「b」繪製到畫布上會更好。視頻遊戲等應用程序應該自行繪製到畫布上。

捏合手勢是密集的,所以它需要在,選擇項b來執行......所以你應該使用@ g00dy解決方案或類似的任何方法。

Here是引用的文檔。

我希望它能幫助你。

+1

setScaleX(或alpha或tranx/y)是通過不創建重新創建顯示列表來優化的,因爲它只需要使父項的顯示列表無效。其次使用它應該在GPU上進行縮放的層。因此理論上它應該比重畫每一幀更快(這相當於重新創建DL)。 –

+1

你是否也讀過我對gOOd的評論的評論?該解決方案僞造它,因爲我只是在顯示縮放(這是一個微不足道的問題)而不是有趣的,但創建一個通用的縮放容器(方式更難的問題),其中所有的孩子有適當的剪輯和觸摸點轉換(以及顯示縮放)。我可以做到這一點,我完全控制了容器的矩陣操作,但我想避免這種情況,因爲那是什麼scaleX和scaleY屬性在第一位(引入api 11+) –

+0

那麼......首先,你的問題是「爲什麼閃爍「,那麼你有你的答案,其實我不在乎你想做什麼。如果您不喜歡@ g00dy解決方案,就像我之前說過的那樣,您可以使用任何其他方法。其次,「繪製到畫布上」沒有比這更快的速度,這就是爲什麼電子遊戲公司總是使用畫布動態更新其圖形框架的原因。 –

3

閃爍看起來像是視圖在縮放還是非縮放之間來回翻轉?這是由於ScaleGestureDetector處理來自您縮放的相同視圖的運動事件造成的。當setScaleX()改變觸摸的座標時,觸發新的觸摸事件被解釋爲反轉剛剛應用的縮放。

將您的可縮放視圖的內容放入單個子女FrameLayout中,並在該視圖上設置縮放比例。

我已經張貼在這裏工作捏縮放配置:https://gist.github.com/anorth/9845602

0

我面臨同樣的問題。現在的任務是:

  • 在其上創建畫布(在視圖或SurfaceView的子類,無所謂)
  • 繪製一些圖像和圖形原語(與方法drawBitmap()的drawLine()...)
  • 化妝帆布滾動和scallable

我認爲,沒有必要在這裏顯示所有的類代碼。

在縮小手勢期間閃爍問題的解決方案非常簡單。 只需將縮放程序放入onScaleEnd()方法中的即可。

private class MyScaleGestureListener implements OnScaleGestureListener 
{ 
    public boolean onScale(ScaleGestureDetector detector) 
    { 
     scaleFactor *= detector.getScaleFactor(); // class variable of type float 
     if (scaleFactor > 5) scaleFactor = 5;  // some limitations 
     if (scaleFactor < 1) scaleFactor = 1; 
     return true; 
    } 
    public boolean onScaleBegin(ScaleGestureDetector detector) 
    { return true;} 

    public void onScaleEnd(ScaleGestureDetector detector) 
    { 
     setScaleX(scaleFactor); setScaleY(scaleFactor); 
     invalidate();  // it seems to me - no effect 
    } 
} 

在真實設備上測試三星GALAXY S III mini。

相關問題