2011-07-21 17 views
8

所以我擴展自定義SurfaceView,並試圖讓它具有捏縮放和滾動功能。如何限制我的畫布的平移矩陣?

我怎麼滾動:

@Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, 
      float distanceX, float distanceY) { 

     // subtract scrolled amount 
     matrix.postTranslate(-distanceX, -distanceY); 

     rebound(); 

     invalidate(); 

     // handled 
     return true; 
    } 

我怎麼放大:

@Override 
    public boolean onScale(ScaleGestureDetector detector) { 
     if (detector.isInProgress()) { 
      // get scale 
      float factor = detector.getScaleFactor(); 

      // Don't let the object get too small or too large. 
      if (factor * scale > 1f) { 
       factor = 1f/scale; 
      } else if (factor * scale < minScale) { 
       factor = minScale/scale; 
      } 

      // store local scale 
      scale *= factor; 

      // do the scale 
      matrix.preScale(factor, factor, detector.getFocusX(), detector.getFocusY()); 

      rebound(); 

      invalidate(); 
     } 

     return true; 
    } 

(僅供參考我使用此代碼爲onDraw :)

@Override 
protected void onDraw(Canvas canvas) { 
    super.onDraw(canvas); 

    canvas.save(); 
    canvas.setMatrix(matrix); 
    // [...] stuff drawn with matrix settings 
    canvas.restore(); 
    // [...] stuff drawn without matrix settings, as an overlay 
} 

目前這兩種方法是運作良好。縮放停止在最小值(0f和1f之間)和最大值(當前總是1f)的比例值。使用

全局字段:

  • drawWdrawH = float,其大小在中規模畫布數據的像素= 1
  • parentWparentH = float,在可見視圖的像素的尺寸。
  • matrix = android.graphics.Matrix

的問題是「rebound()」(也許需要一個更好的名字,嘿嘿)方法我試圖實施將自動強制的內容留在視圖中。

我嘗試過各種方法來嘗試計算邊界應該在哪裏(在矩形(0,0,parentW,parentH)內),並且在矩陣變得太遠時將其轉換回來。

這是我現在擁有的東西,絕對不行,反而把它推向更遠的地方。我覺得問題是我的數學問題,而不是我的想法。 有人可以提出更簡單或更乾淨的代碼,如果它的太遠和/或解決我的嘗試在這個實現的問題解決矩陣到邊緣?的,如果用來做它出現在頂部檢查左

public void rebound() { 
    // bounds 
    RectF currentBounds = new RectF(0, 0, drawW, drawH); 
    matrix.mapRect(currentBounds); 
    RectF parentBounds = new RectF(0, 0, parentW, parentH/2); 

    PointF diff = new PointF(0, 0); 

    if (currentBounds.left > parentBounds.left) { 
     diff.x += (parentBounds.left - currentBounds.left); 
    } 
    if (currentBounds.top > parentBounds.top) { 
     diff.y += (parentBounds.top - currentBounds.top); 
    } 
    if (currentBounds.width() > parentBounds.width()) { 
     if (currentBounds.right < parentBounds.right) { 
      diff.x += (parentBounds.right - currentBounds.right); 
     } 
     if (currentBounds.bottom < parentBounds.bottom) { 
      diff.y += (parentBounds.bottom - currentBounds.bottom); 
     } 
    } 

    matrix.postTranslate(diff.x, diff.y); 
} 

先前的版本,我寫的矩陣是一個前場(我只是用canvas.scale()然後onDrawcanvas.translate()),其工作:

public void rebound() { 
    // bounds 
    int boundTop = 0; 
    int boundLeft = 0; 
    int boundRight = (int)(-scale * drawW + parentW); 
    int boundBottom = (int)(-scale * drawH + parentH); 

    if (boundLeft >= boundRight) { 
     mScrollX = Math.min(boundLeft, Math.max(boundRight, mScrollX)); 
    } else { 
     mScrollX = 0; 
    } 
    if (boundTop >= boundBottom) { 
     mScrollY = Math.min(boundTop, Math.max(boundBottom, mScrollY)); 
    } else { 
     mScrollY = 0; 
    } 
} 

我正在使用新方法,以便我可以正確縮放以detector.getFocusX(),detector.getFocusY()爲中心。

UPDATE:我改變了現在的方法。它只起作用,仍然限制y方向偏離中心,並且在改變縮放級別後錯誤。我也做了「preScale」和「postTranslate」,這樣(據我瞭解),它應該始終應用縮放比例,而不是混合它們。

FINAL UPDATE:現在可以使用。這裏有一個工作rebound方法與評論:

public void rebound() { 
    // make a rectangle representing what our current canvas looks like 
    RectF currentBounds = new RectF(0, 0, drawW, drawH); 
    matrix.mapRect(currentBounds); 
    // make a rectangle representing the scroll bounds 
    RectF areaBounds = new RectF((float) getLeft(), 
            (float) getTop(), 
            (float) parentW + (float) getLeft(), 
            (float) parentH + (float) getTop()); 

    // the difference between the current rectangle and the rectangle we want 
    PointF diff = new PointF(0f, 0f); 

    // x-direction 
    if (currentBounds.width() > areaBounds.width()) { 
     // allow scrolling only if the amount of content is too wide at this scale 
     if (currentBounds.left > areaBounds.left) { 
      // stop from scrolling too far left 
      diff.x = (areaBounds.left - currentBounds.left); 
     } 
     if (currentBounds.right < areaBounds.right) { 
      // stop from scrolling too far right 
      diff.x = (areaBounds.right - currentBounds.right); 
     } 
    } else { 
     // negate any scrolling 
     diff.x = (areaBounds.left - currentBounds.left); 
    } 

    // y-direction 
    if (currentBounds.height() > areaBounds.height()) { 
     // allow scrolling only if the amount of content is too tall at this scale 
     if (currentBounds.top > areaBounds.top) { 
      // stop from scrolling too far above 
      diff.y = (areaBounds.top - currentBounds.top); 
     } 
     if (currentBounds.bottom < areaBounds.bottom) { 
      // stop from scrolling too far below 
      diff.y = (areaBounds.bottom - currentBounds.bottom); 
     } 
    } else { 
     // negate any scrolling 
     diff.y = (areaBounds.top - currentBounds.top); 
    } 

    // translate 
    matrix.postTranslate(diff.x, diff.y); 
} 

它否定了,我不通過翻譯回邊界想要的任何滾動。如果內容太小,則會完全否定滾動,從而迫使內容位於左上角。

回答

0

我實現了一個完全像這樣的東西來滾動我自己的捏縮放。我懷疑你的y軸偏離中心的問題可能是視圖不是全屏大小,或者你可能沒有改變座標來匹配比例。

我的實現計算比例因子,並將其應用於: canvas.scale(pinchZoomScale,pinchZoomScale);然後計算屏幕的物理大小(以像素爲單位),將其轉換爲米,最後應用縮放因子,以便所有繪製的對象都正確偏移。

這個實現依賴於總是知道什麼應該在屏幕的中心並鎖定它,無論縮放級別如何。

+0

你說得對!該視圖不是整個屏幕大小。矩陣轉換是相對於屏幕而不是畫布視圖嗎?我認爲它是最有意義的是相對於畫布而不是屏幕... – Ribose

+0

矩陣是相對於畫布,但它錨定在位置0,0,所以倍增的比例和畫東西到5,5將使它看起來是在2.5,2.5 我發現在某些情況下,視圖大小可能會感到困惑,並嘗試使用屏幕大小作爲指導,而不是您操縱的實際視圖。花了很多試驗和錯誤才能讓我的縮放比例適合畫布上對象位置的縮放比例。 – ScouseChris

+1

謝謝!隨着大量的試驗和錯誤,我確實得到它終於工作。 – Ribose