2013-12-08 26 views
3

我對編碼相當陌生,並且是全新的圖形。我會感激一些方向,因爲我一直無法找到我需要的答案。Android - 如何在縮放後找到矩形

我有一個擴展視圖的類。我在自定義畫布中創建了幾個3層結構的矩形。我成功地能夠觸摸並移動每個矩形。我可以平移整個畫布。在我平移之後,我可以移動單個矩形。我可以放大整個屏幕。我不能做的一件事是在縮放之後移動單個矩形。縮放後我無法「找到」反光板。我準備放棄整個自定義視圖,並嘗試使用imageview或者我可以處理的事情來嘗試查看座標所觸及的內容。

我的問題是:你怎麼在縮放後找到矩形的座標?我的猜測是基於畫布的移動或畫布的比例來重新計算每一個矩形,但顯然我錯過了一些東西,因爲這看起來過於複雜,並且不適合我。

下面是一些代碼 - 請原諒這個爛攤子,我只是想讓這個想法失敗。我嘗試過使用矩陣以及計算器中的比例因子,但都沒有讓我處於正確的位置。 (某些代碼不使用 - 我用它,但不能得到它來計算,其中rects是正確的......如果可以的,甚至這樣做的正確方法?)

protected void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     canvas.translate(xOffset, yOffset); 
     canvas.scale(scaleFactor, scaleFactor); 
     for (RectF r: RectFs){ 
      paint.setStyle(Paint.Style.STROKE); 
      paint.setColor(Color.BLACK); 
      canvas.drawRoundRect(r, 20, 20,paint); //Set a border 

      paintShader.setStyle(Style.FILL); 
      paintShader.setShader(new LinearGradient(r.left, r.bottom, r.right, r.top, Color.CYAN, Color.YELLOW, Shader.TileMode.REPEAT)); 
      canvas.drawRoundRect(r, 20, 20, paintShader);     

      paint.setColor(Color.BLACK); 
      paint.setTextSize(textSize); 
      paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); 
      paint.setLinearText(true); 
      canvas.drawText(text, r.left+px, r.top+py, paint); 
     } 
    } 

    public boolean onTouchEvent(MotionEvent event) { 
     scaleGestureDetector.onTouchEvent(event); 
     touched = true; 

     if (!panned){ 
      left = event.getX() - rectHeight/2; 
      top = event.getY() - rectWidth/2; 
     } 
     switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       startPos.set(event.getX(), event.getY()); 
       findWhatWasTouched(); 
       invalidate(); 
       break; 
      case MotionEvent.ACTION_POINTER_DOWN: 

      case MotionEvent.ACTION_MOVE: 
       if (freezeAction) 
        break; 
       // Only move if the ScaleGestureDetector isn't processing a gesture. 
       if (!scaleGestureDetector.isInProgress() && panned) { 
        xOffset += event.getX() - startPos.x; 
        yOffset += event.getY() - startPos.y; 
       } else 
        resetAllRectsAfterScrollOrZoom(); 
       findWhatWasTouched(); 
       invalidate(); 
       startPos.set(event.getX(), event.getY()); 
       break; 
      case MotionEvent.ACTION_POINTER_UP: 
       freezeAction = true;// When two fingers off of zoom, don't let the other finger jump everything around 
       break; 
      case MotionEvent.ACTION_UP: 
       if (!freezeAction){      
        findWhatWasTouched(); 
        invalidate(); 
        if (panned || zoomed) 
         resetAllRectsAfterScrollOrZoom(); 
       }    
       liveRect = null; 
       panned = false; 
       freezeAction = false; 
       xOffset = 0; 
       yOffset =0; 
       break; 
     } 
     return true; 
    } 

    public void resetAllRectsAfterScrollOrZoom(){ 
     float height, width; 
     for (RectF r: RectFs){ 
      height = r.height(); 
      width = r.width(); 
      if (zoomed){ 
       r.left += (xOffset * scaleFactor); 
       r.top += (yOffset * scaleFactor); 
      }else { 
       r.left += xOffset; 
       r.top += yOffset ; 
      } 
          r.right = r.left + width; 
      r.bottom = r.top + height; 
     } 
    } 

    public void findWhatWasTouched(){ 
     boolean rectWasTouched = false; 
     for (RectF r: RectFs){ // Update positions due to a touch event. 
      if (r.contains(startPos.x, startPos.y)){ 
       if (liveRect == null) 
        liveRect = r; 
       rectWasTouched = true; 
      } 
     } 
     if (!rectWasTouched) 
      panned = true; 
     if (!zoomed && !panned && liveRect != null){ 
      float height = liveRect.height(); 
      float width = liveRect.width(); 
      liveRect.left = left; 
      liveRect.top = top; 
      liveRect.right = liveRect.left + width; 
      liveRect.bottom = liveRect.top + height; // We have a moving single rect - reset it's position here 
     } 
    } 

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { 
      @Override 
      public boolean onScale(ScaleGestureDetector detector) { 
       scaleFactor *= detector.getScaleFactor(); 
       zoomed = true;  
       // don't let the object get too small or too large. 
       scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 5.0f)); 
       return true; 
      } 
      @Override 
      public void onScaleEnd(ScaleGestureDetector detector){ 
       zoomed = false; 
      } 
    } // End ScaleListener class 
} // End view class 

最大的問題是因爲在縮放之後觸摸了rects,當我朝那個方向移動時,將revers進一步向下移動&,呈指數形式......這導致我認爲resetAllRects塊的縮放部分中的數學錯誤。但對於我的生活,我無法弄清楚。仍然不知道是否每次重置矩形座標是否是正確的方法?

回答

1

這花了我好幾天的時間來解決,而且我不認爲我可以在沒有SO的情況下找到答案。特別感謝@Awais Tariq給我這裏所需的線索:Get Canvas coordinates after scaling up/down or dragging in android。基本上所有的東西(動作,翻譯,最重要的是,檢查指針位置)必須通過可以翻譯新的屏幕密度的計算。這是我改變的情況,以防萬一任何人遇到這樣的混亂:

liveRect.left = (startPos.x/scaleFactor + clipbounds.left) - width/2; 
liveRect.top = (startPos.y/scaleFactor + clipbounds.top)- height/2; 
liveRect.right = liveRect.left + width; 
liveRect.bottom = liveRect.top + height; 

這將在縮放後重新演示rects的位置。但隨着距離0,0越來越遠,指針也呈指數關係。要糾正,我裏面用下面的公式,如果檢查,看看有什麼被感動了:

if (r.contains(startPos.x/scaleFactor + clipbounds.left, startPos.y/scaleFactor + clipbounds.top)) 

一切都成功地與該解決方案的工作。我可能會回過頭來嘗試使用佈局,以查看if-check中的傳遞是否更容易。但是,現在,這是有效的。對於我的新手編碼大腦來說,這太複雜了,我想知道這是不是可以在未來安裝到Android中的東西。

0
float[] f = new float[9]; 
    imageView.getImageMatrix().getValues(f); 

    Drawable d = imageView.getDrawable(); 
    Rect r = d.getBounds(); 

    float transX = f[Matrix.MTRANS_X]; 
    float transY = f[Matrix.MTRANS_Y]; 

    float scaleX = f[Matrix.MSCALE_X]; 
    float scaleY = f[Matrix.MSCALE_Y]; 

    // rect coordinates 
    float x0 = transX; 
    float y0 = transY; 
    float x1 = scaleX * (r.right - r.left); 
    float y1 = scaleY * (r.bottom - r.top)