Android - 如何在缩放后找到一个矩形

3

我对编程还比较新,对图形编程更是一窍不通。我希望能得到一些指导,因为我找不到我需要的答案。

我有一个扩展视图的类。我在自定义画布上创建了几个三层矩形。我可以成功地触摸和移动每个矩形。我可以平移整个画布。我可以在平移后移动单个矩形。我可以缩放整个屏幕。唯一不能做到的是,在缩放后移动单个矩形。我无法“找到”缩放后的矩形。我已经准备放弃整个自定义视图,并尝试使用imageview或其他我可以控制的东西来完成此操作,而不是通过坐标查看被触摸的内容。

我的问题是:如何找到缩放后矩形的坐标?我的猜测是基于画布的移动或缩放重新计算每个矩形,但很明显我错过了什么,因为这似乎过于复杂,并且对我没有用。

以下是一些代码 - 请原谅混乱,我只是想把思路表达出来。我尝试使用矩阵以及缩放因子进行计算,但是两者都似乎没有让我到达正确的位置。(一些代码没有使用 - 我用了它,但无法正确计算矩形的位置...如果这甚至是正确的方法?)

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

最大的问题是,在缩放后,矩形的触摸会呈指数级地向下和向右移动...这让我想到重置所有矩形块中的缩放部分的数学计算可能有误。但是我无论如何都无法弄清楚。仍然不知道每次重置矩形坐标是否是正确的做法?

2个回答

1

这让我花了好几天时间来整理,如果没有SO的帮助,我觉得我永远不可能弄清楚。特别感谢@Awais Tariq在这里给了我所需的线索:在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;  

这将在缩放后重新计算矩形的位置。但是,随着距离0,0越远,指针也会呈指数级偏差。为了纠正这一点,在if语句中使用以下公式来查看所触摸的内容:
if (r.contains(startPos.x  / scaleFactor + clipbounds.left, startPos.y  / scaleFactor + clipbounds.top))

这个解决方案一切正常。我可能会回头尝试使用布局来看看是否将视图传递到if检查中可能更容易。但是,现在它可以工作了。对于我这种新手编码者来说,这太复杂了,我想知道这是否可以在未来内置到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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接