帆布捏缩放点内的界限 [英] Canvas Pinch-Zoom to Point Within Bounds

查看:116
本文介绍了帆布捏缩放点内的界限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经被困在这个问题上八个小时,所以我想是时候得到一些帮助。

I've been stuck on this problem for eight hours, so I figured it was time to get some help.

在我开始了我的问题,我只是让大家知道,我已经通过我发现帮助的答案本网站和谷歌,并没有。 (的是,<一个href="http://stackoverflow.com/questions/6835224/android-bitmap-canvas-offset-after-scale">another,和<一href="http://stackoverflow.com/questions/6624103/scaling-image-of-imageview-while-maintaining-center-point-in-same-place">another.)

Before I begin my problem, I'll just let it be known that I've been through this site and Google, and none of the answers I've found have helped. (This is one, another, and another.)

这里的交易:我有一个扩展的类 SurfaceView (姑且称之为 MySurface ),并覆盖很多方法在里面。通常情况下,绘制了几个广场和文本框,这是所有罚款。一旦用户开始触摸,将其转换为位图,然后绘制每一帧,直到用户释放。

Here's the deal: I have a class that extends SurfaceView (let's call it MySurface) and overrides many methods in it. Normally, it draws several squares and text boxes, which is all fine. As soon as a user starts touching, it converts to a Bitmap, then draws each frame that until the user releases.

下面的难题是:我想要实现这样的功能,用户可以将两个手指放在屏幕上,捏放大,并且还平移(但只能用两个手指)

Here's the rub: I want to implement such a functionality that the user can place two fingers on the screen, pinch to zoom, and also pan around (but ONLY with two fingers down).

我发现捏到变焦几个实现和适应他们给我的画布对象 MySurface 通过如下:

I found a few implementations of pinch-to-zoom and adapted them to my Canvas object in MySurface via the following:

public void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();

    canvas.scale(mScaleVector.z, mScaleVector.z); // This is the scale factor as seen below
    canvas.translate(mScaleVector.x, mScaleVector.y); // These are offset values from 0,0, both working fine

    // Start draw code

    // ...

    // End draw code

    canvas.restore();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float factor = detector.getScaleFactor();
        if (Math.abs(factor - 1.0f) >= 0.0075f) {
            mScaleVector.z *= factor;
            mScaleVector.z = Math.max(MIN_ZOOM, Math.min(mScaleVector.z, MAX_ZOOM));
        }

        // ...

        invalidate();

        return true;
    }
}
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction() & MotionEvent.ACTION_MASK;
    int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    if (event.getPointerCount() == 2) {
        if (action == MotionEvent.ACTION_POINTER_DOWN && pointerIndex == 1) {
            // The various pivot coordinate codes would belong here
        }
    }

    detector.onTouchEvent(event); // Calls the Scale Gesture Detector
    return true;
}

虽然这两个元素很好地工作 - 在来回滚动和双指缩放 - 有一个大问题。在双指缩放,使用时,放大到该点 0,0 而不是放大到手指点,

While both elements work fine--the scrolling back and forth and the pinch-to-zoom--there is one large problem. The pinch-to-zoom, when used, zooms into the point 0,0, instead of zooming into the finger point.

我已经尝试了很多办法来解决这个问题:

I've tried a lot of ways to fix this:

  • 使用 canvas.scale(mScaleVector.z,mScaleVector.z,mScaleVector.x,mScaleVector.y); ;显然,这会产生不想要的结果为 mScaleVector x和y的值是0的偏移量。
  • 在管理一个支点坐标使用相同的偏移量为翻译()的方法,但这会产生是同一个 0,0 问题,或者跳来跳去视图时感动。
  • 在许多其他的事情......我已经做了很多与上述支点协调,努力的基础上为用户的触摸位置,并移动它相对于该触摸每个连续的手势。
  • Using canvas.scale(mScaleVector.z, mScaleVector.z, mScaleVector.x, mScaleVector.y);; obviously, this produces unwanted results as the mScaleVector x and y values are 0-offsets.
  • Managing a "pivot" coordinate that uses the same offset as the translate() method, but this produces either the same 0,0 issue, or jumping around when the view is touched.
  • Numerous other things... I've done a lot with the aforementioned pivot coordinate, trying to base its location on the user's first touch, and moving it relative to that touch each successive gesture.

此外,此帆布必须有界的,所以用户不能滚动永远。然而,当我使用 .scale(SX,SY,PX,PY)方法,它远不止我在 .translate设定任何界限的事情( )

Additionally, this canvas must be bounded, so the user cannot scroll forever. However, when I use the .scale(sx, sy, px, py) method, it pushes things beyond any bounds I set in .translate().

我... pretty的在这一点东西多开。我知道这个功能可以增加,因为它是(观看单个图像时)出现在Android 4.0的画廊。我试图追查来源$ C ​​$ C处理这个,但没有成功。

I'm... pretty much open to anything at this point. I know this functionality can be added, as it is seen in the Android 4.0 gallery (when viewing a single image). I've tried to track down the source code that handles this, to no avail.

推荐答案

下面是code我用它来实现双指缩放在的ImageView 使用 ScaleGestureDetector 。很少或根本没有修改,你应该能够使用它太,因为你可以使用转换marices也画上一个画布

Here is the code I use to implement pinch zoom in an ImageView using ScaleGestureDetector. With little or no modification you should be able to use it too, since you can use transformation marices too, to draw on a Canvas.

@Override
public boolean onScale(ScaleGestureDetector detector) {
    float mScaleFactor = (float) Math.min(
        Math.max(.8f, detector.getScaleFactor()), 1.2);
    float origScale = saveScale;
    saveScale *= mScaleFactor;
    if (saveScale > maxScale) {
        saveScale = maxScale;
        mScaleFactor = maxScale / origScale;
    } else if (saveScale < minScale) {
        saveScale = minScale;
        mScaleFactor = minScale / origScale;
    }
    right = width * saveScale - width
            - (2 * redundantXSpace * saveScale);
    bottom = height * saveScale - height
            - (2 * redundantYSpace * saveScale);
    if (origWidth * saveScale <= width
            || origHeight * saveScale <= height) {
        matrix.postScale(mScaleFactor, mScaleFactor, width / 2, height / 2);
        if (mScaleFactor < 1) {
            matrix.getValues(m);
            float x = m[Matrix.MTRANS_X];
            float y = m[Matrix.MTRANS_Y];
            if (mScaleFactor < 1) {
                if (Math.round(origWidth * saveScale) < width) {
                    if (y < -bottom)
                        matrix.postTranslate(0, -(y + bottom));
                    else if (y > 0)
                        matrix.postTranslate(0, -y);
                } else {
                    if (x < -right)
                        matrix.postTranslate(-(x + right), 0);
                    else if (x > 0)
                        matrix.postTranslate(-x, 0);
                }
            }
        }
    } else {
        matrix.postScale(mScaleFactor, mScaleFactor, detector.getFocusX(), detector.getFocusY());
        matrix.getValues(m);
        float x = m[Matrix.MTRANS_X];
        float y = m[Matrix.MTRANS_Y];
        if (mScaleFactor < 1) {
            if (x < -right)
                matrix.postTranslate(-(x + right), 0);
            else if (x > 0)
                matrix.postTranslate(-x, 0);
            if (y < -bottom)
                matrix.postTranslate(0, -(y + bottom));
            else if (y > 0)
                matrix.postTranslate(0, -y);
        }
    }
    return true;
}

在我的情况,我计算在视图的 onMeasure()法neccesary值,你可能想在你的 SurfaceView

In my case, I computed the neccesary values in the onMeasure() method of the View, you might want to do this somewhere else in your SurfaceView

width = MeasureSpec.getSize(widthMeasureSpec); // Change this according to your screen size
height = MeasureSpec.getSize(heightMeasureSpec); // Change this according to your screen size

// Fit to screen.
float scale;
float scaleX = (float) width / (float) bmWidth;
float scaleY = (float) height / (float) bmHeight;
scale = Math.min(scaleX, scaleY);
matrix.setScale(scale, scale);
setImageMatrix(matrix);
saveScale = 1f;
scaleMappingRatio = saveScale / scale;

// Center the image
redundantYSpace = (float) height - (scale * (float) bmHeight);
redundantXSpace = (float) width - (scale * (float) bmWidth);
redundantYSpace /= (float) 2;
redundantXSpace /= (float) 2;

matrix.postTranslate(redundantXSpace, redundantYSpace);

origWidth = width - 2 * redundantXSpace;
origHeight = height - 2 * redundantYSpace;
right = width * saveScale - width - (2 * redundantXSpace * saveScale);
bottom = height * saveScale - height - (2 * redundantYSpace * saveScale);
setImageMatrix(matrix);

这一点解释:

saveScale 是当前比例的位图

mScaleFactor 是你要与乘以你的缩放比例因子。

mScaleFactor is the factor you have to multiply your scale ratio with.

maxScale minScale 可以是恒定值。

宽度高度是屏幕的尺寸。

redundantXSpace redundantYSpace 在图像边框和屏幕边框之间的空白,因为图像中居中时,是小然后屏幕

redundantXSpace and redundantYSpace are the empty between the image borders and screen borders since the image is centered when in it is smaller then the screen

origHeight origWidth 是位图的尺寸

基质是用于绘制位图当前变换矩阵

matrix is the current transformation matrix used to draw the bitmap

诀窍是,当我第一次规模化,集中在初始化的形象,我挑选的规模比例为1和 scaleMappingRatio 我映射的实际刻度值相对于所述图像

The trick is, that when I first scaled and centered the image on initialization, I picked that scale ratio to be 1 and with scaleMappingRatio I mapped the actual scale values of the image relative to that.

这篇关于帆布捏缩放点内的界限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆