如何在画布的翻译矩阵上设置限制?

Rib*_*ose 8 java android matrix android-canvas

所以我正在扩展自定义,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;
    }
Run Code Online (Sandbox Code Playgroud)

我如何缩放:

    @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;
    }
Run Code Online (Sandbox Code Playgroud)

(供参考我使用此代码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
}
Run Code Online (Sandbox Code Playgroud)

目前这两种方法都运作良好.缩放最小(在0f和1f之间)和最大(当前始终为1f)刻度值正确停止.

使用的全球字段:

  • drawW,drawH= float,比例= 1的画布数据的像素大小.
  • parentW,parentH= float,可见视图的像素大小.
  • matrix= android.graphics.Matrix.

问题是rebound()我试图实现的" "(可能需要一个更好的名称,heh)方法会自动强制内容保持在视图中.

我已经尝试了各种方法来尝试计算边界应该在哪里(在矩形(0,0,parentW,parentH)内)并且当它走得太远时将矩阵"反向"转换.

这就是我现在所拥有的,这绝对不起作用,而是将它向右推得更远.我觉得问题是我的数学,而不是我的想法.有人可以提出更简单或更清晰的代码,如果它太过分,将矩阵转换为边缘和/或修复我在此实现中尝试的问题吗?if检查用于使其显示在左上角

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);
}
Run Code Online (Sandbox Code Playgroud)

我写的矩阵是一个场前一版本(我只是用canvas.scale()那么canvas.translate()onDraw),其工作:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在使用新的方式,以便我可以正确地缩放detector.getFocusX(),detector.getFocusY().

更新:我将方法改为现在的状态.它只能稍微工作,仍然偏离y方向偏离中心,并且在改变缩放级别后是错误的.我也把它作为"preScale"和"postTranslate",以便(据我所知)它应该始终应用比例然后翻译而不是混合它们.

最终更新:它现在有效.这是一个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);
}
Run Code Online (Sandbox Code Playgroud)

它通过将其转换回边界来否定我不想要的任何滚动.如果内容太小,它会完全否定滚动,从而迫使内容位于左上角.

Sco*_*ris 1

我实现了与此完全相同的东西来滚动我自己的捏合来缩放。我怀疑您的 y 轴偏离中心的问题可能是由于视图不是全屏尺寸,或者您可能没有更改坐标以匹配比例。

我的实现计算比例因子,并将其应用于:canvas.scale(pinchZoomScale,pinchZoomScale); 然后计算屏幕的物理尺寸(以像素为单位),将其转换为米,最后应用缩放因子,以便绘制的所有对象都正确偏移。

此实现依赖于始终了解屏幕中心的内容并锁定它,无论缩放级别如何。