2013-12-08 40 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)