Bug with Android 4.3 ImageView method getImageMatrix()

时光总嘲笑我的痴心妄想 提交于 2019-12-05 06:48:20

I have found what I believe to be the problem. I took a look at the source code for ImageView and discovered the setImageMatrix(Matrix matrix) is saving the matrix in a different field than getImageMatrix() is returning...

Android 4.4 ImageView

public void setImageMatrix(Matrix matrix) {
    // collaps null and identity to just null
    if (matrix != null && matrix.isIdentity()) {
        matrix = null;
    }

    // don't invalidate unless we're actually changing our matrix
    if (matrix == null && !mMatrix.isIdentity() ||
            matrix != null && !mMatrix.equals(matrix)) {
        mMatrix.set(matrix);
        configureBounds();
        invalidate();
    }
}

Here the matrix is being stored in the field mMatrix

public Matrix getImageMatrix() {
    if (mDrawMatrix == null) { //<-- should be mMatrix == null
        return new Matrix(Matrix.IDENTITY_MATRIX);
    }
    return mDrawMatrix; //<-- NOT THE RIGHT FIELD TO RETURN
}

While getImageMatrix() returns mDrawMatrix...

Android 4.1.2 ImageView

public Matrix getImageMatrix() {
    return mMatrix;
}

public void setImageMatrix(Matrix matrix) {
    // collaps null and identity to just null
    if (matrix != null && matrix.isIdentity()) {
        matrix = null;
    }

    // don't invalidate unless we're actually changing our matrix
    if (matrix == null && !mMatrix.isIdentity() ||
            matrix != null && !mMatrix.equals(matrix)) {
        mMatrix.set(matrix);
        configureBounds();
        invalidate();
    }
}

both methods use the same field - mMatrix

So there's the problem right there --- all of a sudden getImageMatrix() is returning the wrong field...

While my previous answer does outline the overall problem, it in fact might not be a bug. As pointed out by Generic Holiday Name, mDrawMatrix should be set to mMatrix in the configureBounds() method - which would eliminate this problem/bug/whatever.

HOWEVER, I had to add several lines of code to get configureBounds() to actually work:

private void configureBounds() {
    if (mDrawable == null || !mHaveFrame) {
        return;
    }

    int dwidth = mDrawableWidth;
    int dheight = mDrawableHeight;

    ...

    if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
        /* If the drawable has no intrinsic size, or we're told to
            scaletofit, then we just fill our entire view.
        */
        mDrawable.setBounds(0, 0, vwidth, vheight);
        mDrawMatrix = null;
    } else {
             //here's the where mDrawMatrix == mMatrix IF using scaleType.MATRIX
             ...
    }
}

So, in order to actually get this to work the way I expect with 4.2 and below you need to make sure:

  1. mDrawable != null. This wasn't a problem before, but for my case I wasn't using a drawable so everything was failing (the return statement was hit right away)
  2. 'dwidth >0 && dheight >0. This isn't a problem if you have a real drawable, but like I said, I didn't.
  3. mHaveFrame = true. I had no idea what this was - never used it. The only way to set this to true is by calling setFrame(int, int, int, int).

To get my scaling code to work again, I had to add the following:

 //potentially a fix for the "bug" that appears in Android 4.3+
 //mDrawable cannot be null anymore for getImageMatrix to work---stupid
 //therefore the imageview class MUST set a drawable for matrix scaling to work
 //so here I am using a "empty" drawable to get around this
 ShapeDrawable fakeDrawable = new ShapeDrawable(); //so mDrawable != null
 fakeDrawable.setIntrinsicHeight(1); //so dwidth and dheight are > 0
 fakeDrawable.setIntrinsicWidth(1);

 setImageDrawable(fakeDrawable);

 setFrame(0, 0, viewWidth, viewHeight); //setting a frame so mHaveFrame = true

YIKES

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!