ImageView的setImageMatrix在某些设备上运行不正常(可能比Android 4.4早)

时间:2015-02-25 13:24:11

标签: android matrix imageview

我试图通过以下代码在触摸事件上移动ImageView:

public class ScrollableImageView extends ImageView {
    private GestureDetectorCompat gestureDetectorCompat;

    public ScrollableImageView(Context context) {
        this(context, null);
    }

    public ScrollableImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScrollableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);

        gestureDetectorCompat = new GestureDetectorCompat(context,
                new MySimpleOnGestureListener(this));
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        gestureDetectorCompat.onTouchEvent(event);
        return true;
    }

    public void scroll(float distance) {
        Matrix imageMatrix = getImageMatrix();
        imageMatrix.postTranslate(distance, 0);
        setImageMatrix(imageMatrix);
        invalidate();
    }

    private static class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
        private ScrollableImageView scrollableImageView;

        public MySimpleOnGestureListener(ScrollableImageView scrollableImageView) {
            this.scrollableImageView = scrollableImageView;
        }

        @Override
        public boolean onDown(MotionEvent e) {
            Utils.log("onDown");
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            scrollableImageView.scroll(-distanceX);
            return true;
        }
    }
}

起初,一切都在Nexus 5(Android 4.4.4和Lollipop)上运行良好。但后来我尝试使用旧版本的Android,如4.0.4(Galaxy S2)或Nexus S(4.1.1)......但这些版本都没有用。

然后经过一段时间的努力,我想出了这个解决方案,它在所有设备上运行良好:

(请注意,现在,我通过本地对象跟踪ImageView的矩阵对象,而不是通过ImageView的getImageMatrix()获取它

public class ScrollableImageView extends ImageView {
    private GestureDetectorCompat gestureDetectorCompat;
    private Matrix imageMatrix;

    public ScrollableImageView(Context context) {
        this(context, null);
    }

    public ScrollableImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ScrollableImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setScaleType(ScaleType.MATRIX);

        imageMatrix = new Matrix();

        gestureDetectorCompat = new GestureDetectorCompat(context,
                new MySimpleOnGestureListener(this));
    }

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) {
        gestureDetectorCompat.onTouchEvent(event);
        return true;
    }

    public void scroll(float distance) {
        imageMatrix.postTranslate(distance, 0);
        setImageMatrix(imageMatrix);
        invalidate();
    }

    private static class MySimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener {
        private ScrollableImageView scrollableImageView;

        public MySimpleOnGestureListener(ScrollableImageView scrollableImageView) {
            this.scrollableImageView = scrollableImageView;
        }

        @Override
        public boolean onDown(MotionEvent e) {
            Utils.log("onDown");
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            scrollableImageView.scroll(-distanceX);
            return true;
        }
    }
}

我得到了解决方案,但我仍然无法理解为什么我以前的代码无效?!

我试图研究,但唯一有意义的是ImageView的getImageMatrix()文档:

  

返回视图的可选矩阵。这适用于视图   绘制时绘制。如果没有矩阵,这个方法会   返回一个单位矩阵。不要改变这个矩阵,但要做   复印件。如果你想要一个不同的矩阵应用于drawable,be   一定要调用setImageMatrix()。

然后通过说Do not change this matrix in place but make a copy让我更加困惑,这样做的重点是什么?为什么我不能像以前的代码那样做? (获取ImageView的当前矩阵然后应用转换,然后通过setImageMatrix()将其设置回来,如文档所述)

有人请给我一些启示,这对我来说太混乱了。

1 个答案:

答案 0 :(得分:3)

好的,伙计们,我明白了!

实际上文档是有道理的。

  

返回视图的可选矩阵。这适用于视图   绘制时绘制。如果没有矩阵,这个方法会   返回一个单位矩阵。 不要更改此矩阵,但要制作   副本。如果你想要一个不同的矩阵应用于drawable,be   一定要调用setImageMatrix()。

由于ics_mr1的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();
    }
}

所以,如果我喜欢:

   Matrix imageMatrix = getImageMatrix();
   imageMatrix.postTranslate(distance, 0);
   setImageMatrix(imageMatrix);

matrix != null && !mMatrix.equals(matrix)将是false,因为我重复使用相同的Matrix对象(这就是文档说Do not change this matrix in place but make a copy的原因),然后什么都不会发生,因为没有条件满足

然后现在我想出了一个非常优雅的解决方案:

   Matrix imageMatrix = new Matrix(getImageMatrix());
   imageMatrix.postTranslate(distance, 0);
   setImageMatrix(imageMatrix);

那是什么 YIKES