我对编码还很陌生,对图形也很陌生。如果能给我一点指导,我会很感激的,因为我还没有找到我需要的答案。
我有一个扩展视图的类。我在自定义画布中创建了几个3层矩形。我能成功地触摸和移动每个矩形。我能把整个画布都煎了。我可以在平移后移动单个矩形。我可以放大整个屏幕。我唯一不能做的就是缩放后移动单个矩形。放大后我找不到直肠。我已经准备好放弃整个自定义视图,尝试使用imageview或其他一些我可以处理的东西来实现这一点vs.尝试查看坐标所触及的内容。
我的问题是:缩放后如何找到矩形的坐标?我的猜测是根据画布的移动或画布的比例重新计算每个矩形,但显然我遗漏了一些东西,因为这看起来过于复杂,对我来说不起作用。
下面是一些代码-请原谅这些乱七八糟的东西,我只是想把这个想法写下来。我试过在calcs中使用矩阵和scalefactor,但都没有找到正确的位置。(有些代码没有使用-我用过,但无法计算矩形的正确位置…如果这是正确的方法?)

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

最大的问题是缩放后对矩形的触摸会使矩形进一步向下移动,当我朝这个方向移动时,它会以指数方式向右移动……这使我认为resetallrects块的zoom部分的数学是错误的。但对于我的生命我无法理解。仍然不知道每次重置rect coords是否是正确的方法?

最佳答案

我花了好几天的时间才弄清楚,我想没有这些我根本就搞不懂。特别感谢@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;

这将在缩放后重新计算矩形的位置。但当你从0,0进一步时,指针也呈指数“关闭”。为了纠正错误,我在if检查中使用了以下公式来查看触摸到了什么:
if (r.contains(startPos.x  / scaleFactor + clipbounds.left, startPos.y  / scaleFactor + clipbounds.top))

所有的事情都成功地解决了这个问题。我可以回去用一个布局来试试这个,看看是否可以更容易地将视图传递给if检查。但是,目前来说,这是可行的。太复杂了,我的新手程序员的大脑无法理解这一点,我想知道这是否是未来可以内置到Android的东西。

09-25 15:31