【问题标题】:Bug with Android 4.3 ImageView method getImageMatrix()Android 4.3 ImageView 方法 getImageMatrix() 的错误
【发布时间】:2013-12-24 05:53:35
【问题描述】:

我最近升级到了 Android 4.4,但我的应用程序的某些功能令人惊讶地停止工作。

我有这段代码用于初始化然后绘制我的自定义视图。基本思想是调整缩放级别,使整个视图适合屏幕。

private void initAtZoomLevel(float zoomLevel){
    ....
    Matrix transformMatrix = new Matrix();
    transformMatrix.setScale(initialZoomLevel, initialZoomLevel);
    float yTransCenter = (screenHeight - mapHeight)/2.0f;
    setImageMatrix(transformMatrix);
}

protected void onDraw(Canvas canvas){

    super.onDraw(canvas);
    float[] values = new float[9];
    getImageMatrix().getValues(values);
    scaleFactor = values[0];
    ....
}

这适用于我拥有的 ANDROID 4.1.2 和 4.2.2 设备

但在 Android 4.4/4.3 getImageMatrix().getValues(values) 上停止工作! 它返回一个单位矩阵,而不是我期望在应用启动时的变换矩阵!

调试打印输出:

4.1.2:@setImageMatrix(transformMatrix)transformMatrix = Matrix{[0.025122833, 0.0, 0.0][0.0, 0.025122833, 566.5][0.0, 0.0, 1.0]}

@getImageMatrix().getValues(values):transformMatrix = Matrix{[0.025122833, 0.0, 0.0][0.0, 0.025122833, 566.5][0.0, 0.0, 1.0]}

4.4:@setImageMatrix(transformMatrix)transformMatrix = Matrix{[0.025122833, 0.0, 0.0][0.0, 0.025122833, 553.0][0.0, 0.0, 1.0]}

@getImageMatrix().getValues(values):transformMatrix = Matrix{[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]}

我环顾四周,似乎找不到任何关于此的文档。不知何故,我的视图的图像矩阵正在被重置; Android 4.4 是否改变了我们应该这样做的方式?有没有其他人遇到过这个问题?

注意:问题似乎源自 Android 4.3 - 在模拟器上运行时也会出现同样的问题

更新:我已经检查了change log from 4.2 to 4.3,但在 Matrix 类上方我看不到任何东西,或者与 View 类相关的任何东西。

更新 2:我的捏拉缩放也不起作用,它使用相同的 setImageMatrix() 方法 - 显然没有粘住,因为 getImageMatrix().getValues() 没有任何反应

【问题讨论】:

  • 尝试在Android版本之间区分getImageMatrix的实际源代码
  • @GenericHolidayName 如果仔细观察,它实际上并没有保存/返回相同的矩阵(getImageMatrixsetImageMatrix 之间的字段名称不同)
  • stackoverflow.com/questions/30446099/… 有谁知道这个问题吗?

标签: android android-custom-view android-4.4-kitkat android-4.3-jelly-bean


【解决方案1】:

我发现了我认为是问题所在。我查看了ImageView 的源代码,发现setImageMatrix(Matrix matrix) 将矩阵保存在与getImageMatrix() 返回不同的字段中...

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();
    }
}

这里的矩阵被存储在 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
}

getImageMatrix() 返回 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();
    }
}

两种方法都使用相同的字段 - mMatrix

所以问题就在那里 --- 突然间getImageMatrix() 返回了错误的字段...

【讨论】:

  • 要尝试解决,请确保您的scaleType 设置为ScaleType.MATRIX。看起来mMatrix 应该被分配给configureBounds() 中的mDrawMatrix 如果 scaleType 设置正确。看起来这实际上是一个修复来强制scaleType而不是一个新的错误。
  • 我可以发誓我在某个地方有那个...是时候去看看这是否是问题所在
  • 你可能是对的。这就是我的样子。以前,是否分配了mDrawMatrix 并不重要,因为它没有返回。
  • 有一行if(ScaleType.MATRIX == mScaleType) {... mDrawMatrix = mMatrix},但是-configureBounds() 的第一行是if (mDrawable == null || !mHaveFrame) { return; }。所以它会立即返回并绕过设置mDrawMatrix = mMatrix
  • 你的drawable是null吗?这绝对可以解释它。
【解决方案2】:

虽然我之前的回答确实概述了整个问题,但实际上它可能不是一个错误。正如通用假日名称所指出的那样,mDrawMatrix 应该configureBounds() 方法中设置为mMatrix - 这将消除这个问题/错误/无论如何。

但是,我必须添加几行代码才能让configureBounds() 实际工作:

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
             ...
    }
}

所以,为了真正让它按照我对 4.2 及以下版本的预期工作,您需要确保:

  1. mDrawable != null。这以前不是问题,但就我而言,我没有使用可绘制对象,所以一切都失败了(return 语句立即被击中)
  2. 'dwidth &gt;0 &amp;&amp; dheight &gt;0。如果你有一个真正的可绘制对象,这不是问题,但就像我说的,我没有。
  3. mHaveFrame = true。我不知道这是什么——从未使用过。将此设置为 true 的唯一方法是调用 setFrame(int, int, int, int)

要让我的缩放代码再次工作,我必须添加以下内容:

 //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

哎呀

【讨论】:

  • 顺便说一句,添加的代码被放置在我的自定义图像视图的构造函数/初始化方法中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多