带有ScaleType的Android 4.3 ImageView:MATRIX

时间:2013-08-03 19:06:41

标签: matrix imageview android-4.3-jelly-bean

我的问题与:

最相似

Android 4.3 ImageView ScaleType.MATRIX

还有回声:

android zoom image using matrix

但是,使用这些答案的解决方案已经解决了我的问题。

我正在使用Mike Ortiz的TouchImageView的修改版本,允许双击和常规缩放手势来缩放我的ImageView。对于Android 4.2.2及更低版本,注释掉“setScaleType(ScaleType.MATRIX)”就好了,图像在ImageView中居中,你可以随意放大和缩小。但是,取消注释会导致ImageView的图像大小不正确。所有这一切都很好,因为我刚离开那条线进行评论,一切正常。

但是,从Android 4.3开始,如果没有setScaleType(ScaleType.MATRIX),则无法进行缩放。所以我不得不取消注释那条线,但是我从未解决的旧问题又回来了。

所以,首先,当我所做的只是设置ScaleType时,为什么我的计算无法产生正确的图像/ ImageView比率?第二,为什么在没有设置比例类型的情况下它会在4.2.2上变焦得很好,但在4.3上,它不会?最后,有人可以给我一些资源来了解更多关于ScaleType.MATRIX真正做的事情吗?我已经阅读了一些消息来源,并做了一些谷歌搜索,但并没有完全掌握它。

提前感谢您,以及以下代码。

public class TouchImageView extends ImageView {

Matrix matrix = new Matrix();

// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;

// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
float minScale = 1f;
float maxScale = 10f;
float[] floatArray;

float unusedWidth, unusedHeight;

float imageViewWidth, imageViewHeight;
float initialScale = 1f;
float right, bottom, origWidth, origHeight, imageWidth, imageHeight;

boolean zoomedInLastTime = false;
PointF zoomCenter;

ScaleGestureDetector mScaleDetector;
GestureDetector mDetector;

Context context;

public TouchImageView(Context context) {
    super(context);
    sharedConstructing(context);
}

public TouchImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
    sharedConstructing(context);
}

private void sharedConstructing(Context context) {
    super.setClickable(true);
    this.context = context;
    setScaleType(ScaleType.MATRIX);
    //matrix = this.getImageMatrix();
    mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());

    //this is an empty GestureDetector
    mDetector = new GestureDetector(this.context, new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent motionEvent) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onSingleTapUp(MotionEvent motionEvent) {
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
            return false;
        }

        @Override
        public void onLongPress(MotionEvent motionEvent) {

        }

        @Override
        public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
            return false;
        }
    }, null, true);
    mDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener(){

        @Override
        public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
            return false;
        }

        @Override
        public boolean onDoubleTap(MotionEvent motionEvent) {
            Log.d("TouchImageView", "double tap heard");
            PointF currentTapLocation = new PointF(motionEvent.getX(), motionEvent.getY());
            if (!zoomedInLastTime){
                (new ScaleListener()).scaleIt(3f,currentTapLocation.x,currentTapLocation.y);
                zoomCenter = currentTapLocation;
                zoomedInLastTime = true;
            }else {
                (new ScaleListener()).scaleIt(.33f, zoomCenter.x, zoomCenter.y);
                zoomedInLastTime = false;
            }
            return true;
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent motionEvent) {
            return false;
        }
    });
    matrix.setTranslate(1f, 1f);
    floatArray = new float[9];
    setImageMatrix(matrix);

    setOnTouchListener(new DoubleTapPinchZoomListener());
}

@Override
public void setImageBitmap(Bitmap bm) { 
    super.setImageBitmap(bm);
    if(bm != null) {
        if (Build.VERSION.SDK_INT > 17){
            imageWidth = bm.getWidth();
            imageHeight = bm.getHeight();
        } else {
            imageWidth = 2*bm.getWidth();
            imageHeight = 2*bm.getHeight();
        }
    }
}

public void setMaxZoom(float x)
{
    maxScale = x;
}

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector) {
        mode = ZOOM;
        return true;
    }

    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        float mScaleFactor = detector.getScaleFactor();
        scaleIt(mScaleFactor, detector.getFocusX(), detector.getFocusY());
        return true;
    }

    public void scaleIt(float mScaleFactor, float focusx, float focusy){
        float origScale = initialScale;
        initialScale *= mScaleFactor;
        if (initialScale > maxScale) {
            initialScale = maxScale;
            mScaleFactor = maxScale / origScale;
        } else if (initialScale < minScale) {
            initialScale = minScale;
            mScaleFactor = minScale / origScale;
        }
        right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
        bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
        if (origWidth * initialScale <= imageViewWidth || origHeight * initialScale <= imageViewHeight) {
            matrix.postScale(mScaleFactor, mScaleFactor, imageViewWidth / 2, imageViewHeight / 2);
            if (mScaleFactor < 1) {
                matrix.getValues(floatArray);
                float x = floatArray[Matrix.MTRANS_X];
                float y = floatArray[Matrix.MTRANS_Y];
                if (mScaleFactor < 1) {
                    if (Math.round(origWidth * initialScale) < imageViewWidth) {
                        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, focusx, focusy);
            matrix.getValues(floatArray);
            float x = floatArray[Matrix.MTRANS_X];
            float y = floatArray[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);
            }
        }
    }
}

@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    imageViewWidth = MeasureSpec.getSize(widthMeasureSpec);
    imageViewHeight = MeasureSpec.getSize(heightMeasureSpec);

    /*RectF drawableRect = new RectF(0, 0, imageWidth, imageHeight);
    RectF viewRect = new RectF(0, 0, imageViewWidth, imageViewHeight);

    //draw the image in the view
    matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.CENTER);*/

    //Fit to screen.
    float scale;
    float scaleX =  (float) imageViewWidth / (float)(imageWidth);
    float scaleY = (float) imageViewHeight / (float)(imageHeight);
    scale = Math.min(scaleX, scaleY);
    matrix.setScale(scale, scale);
    setImageMatrix(matrix);
    initialScale = 1f;

    // Center the image
    unusedHeight = (float) imageViewHeight - (scale * (float) imageHeight) ;
    unusedWidth = (float) imageViewWidth - (scale * (float) imageWidth);
    unusedHeight /= (float)2;
    unusedWidth /= (float)2;

    matrix.postTranslate(unusedWidth, unusedHeight);

    origWidth = imageViewWidth - 2 * unusedWidth;
    origHeight = imageViewHeight - 2 * unusedHeight;
    right = imageViewWidth * initialScale - imageViewWidth - (2 * unusedWidth * initialScale);
    bottom = imageViewHeight * initialScale - imageViewHeight - (2 * unusedHeight * initialScale);
    setImageMatrix(matrix);
}

class DoubleTapPinchZoomListener implements OnTouchListener {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        mScaleDetector.onTouchEvent(event);

        mDetector.onTouchEvent(event);

        matrix.getValues(floatArray);
        float x = floatArray[Matrix.MTRANS_X];
        float y = floatArray[Matrix.MTRANS_Y];
        PointF curr = new PointF(event.getX(), event.getY());

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                last.set(event.getX(), event.getY());
                start.set(last);
                mode = DRAG;
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG) {
                    float deltaX = curr.x - last.x;
                    float deltaY = curr.y - last.y;
                    float scaleWidth = Math.round(origWidth * initialScale);
                    float scaleHeight = Math.round(origHeight * initialScale);
                    if (scaleWidth < imageViewWidth) {
                        deltaX = 0;
                        if (y + deltaY > 0)
                            deltaY = -y;
                        else if (y + deltaY < -bottom)
                            deltaY = -(y + bottom); 
                    } else if (scaleHeight < imageViewHeight) {
                        deltaY = 0;
                        if (x + deltaX > 0)
                            deltaX = -x;
                        else if (x + deltaX < -right)
                            deltaX = -(x + right);
                    } else {
                        if (x + deltaX > 0)
                            deltaX = -x;
                        else if (x + deltaX < -right)
                            deltaX = -(x + right);

                        if (y + deltaY > 0)
                            deltaY = -y;
                        else if (y + deltaY < -bottom)
                            deltaY = -(y + bottom);
                    }
                    matrix.postTranslate(deltaX, deltaY);
                    last.set(curr.x, curr.y);
                }
                break;

            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                break;
        }
        setImageMatrix(matrix);
        invalidate();
        return true;
    }
}
}

1 个答案:

答案 0 :(得分:1)

事实证明这个问题与MATRIX缩放无关,尽管这对我来说仍然有些神秘。问题是“自动化”重新缩放。我把我的图像放在'drawable'文件夹中,Android会自动缩放到'最适合屏幕大小'。有关这方面的更多信息,请参见此处:

http://developer.android.com/guide/practices/screens_support.html#support

解决方案是将图像放入drawable-nodpi中。这告诉Android NOT根据屏幕大小重新缩放,因此,手动操纵缩放不会与Android自身的缩放冲突。