Photoview: How to restore image's location after setImageBitmap() ?

Created on 29 Jan 2016  路  7Comments  路  Source: Baseflow/PhotoView

I am using PhotoView in my project, every two second I will setting a new bitmap to PhotoView, then I called setScale() to restore scale size, but I can't find any method to restore location. how can I restore image location after change bitmap?(even though the two image has different size)

Most helpful comment

I also tried the getDisplayMatrix / setDisplayMatrix after setting a new ImageDrawable to get the same viewport and it didn't work. The problem with the code is that the getter returns the DRAW matrix (which is given to the imageView) which is the concatenation of mBaseMatrix and mSuppMatrix, while the setter only sets the mSuppMatrix which later gets multiplied by mBaseMatrix. So the mBaseMatrix gets applied many times.

In the end I fixed it in my project by adding a getSuppMatrix() method to PhotoViewAttacher and applying the result using setDisplayMatrix:

// In PhotoViewAttacher.java
public Matrix getSuppMatrix() {
    return new Matrix(mSuppMatrix);
}

// In the Fragment.java
matrixToReapply = photoViewAttacher.getSuppMatrix();
photoView.setImageDrawable(drawable);
photoViewAttacher.setDisplayMatrix(matrixToReapply);

All 7 comments

I trying to using get/setDisplayMatrix() but it seems not correct, image becoming bigger and bigger

After serveral hour's trying,I solved this problem.The key point is to calculate the offset between the original visible rect and the visible rect after call setScale method.So I calculate both 2 rects' center point's offset to the left-top point of the displayrect,then calculate their offset.finally drag the photo view.

`

       float scaleValue = mAttacher.getScale();
        RectF rectF = mAttacher.getDisplayRect();
        float xPrev = (float) (mImageView.getWidth()/2.0 - rectF.left); // this referes to onSingleTapConfirmed in DefaultOnDoubleTapListener.java
        float yPrev = (float) (mImageView.getHeight()/2.0 - rectF.top);

        refreshUI();

        mAttacher.setScale(scaleValue,false);
        rectF = mAttacher.getDisplayRect();
        float xAfter = (float) (mImageView.getWidth()/2.0 - rectF.left);
        float yAfter = (float) (mImageView.getHeight()/2.0 - rectF.top);
        mAttacher.onDrag(xAfter - xPrev,yAfter - yPrev);`

Thanks.I'm using getDisplayMatrix and solved this problem too. the point is Matrix multiplication is not commutative. code's here

//before setImageBitmap()
float scale = getScale();
Matrix matrix = getDisplayMatrix();
float[] values = new float[9];
matrix.getValues(values);

//after setImageBitmap()
matrix.setScale(scale, scale);
matrix.postTranslate(values[2], values[5]);
setDisplayMatrix(matrix);

I also tried the getDisplayMatrix / setDisplayMatrix after setting a new ImageDrawable to get the same viewport and it didn't work. The problem with the code is that the getter returns the DRAW matrix (which is given to the imageView) which is the concatenation of mBaseMatrix and mSuppMatrix, while the setter only sets the mSuppMatrix which later gets multiplied by mBaseMatrix. So the mBaseMatrix gets applied many times.

In the end I fixed it in my project by adding a getSuppMatrix() method to PhotoViewAttacher and applying the result using setDisplayMatrix:

// In PhotoViewAttacher.java
public Matrix getSuppMatrix() {
    return new Matrix(mSuppMatrix);
}

// In the Fragment.java
matrixToReapply = photoViewAttacher.getSuppMatrix();
photoView.setImageDrawable(drawable);
photoViewAttacher.setDisplayMatrix(matrixToReapply);

I think it should be considered as a bug... I ended up using reflexion to fix it using @zaichang approach:

try {
Field f = photoViewAttacher.getClass().getDeclaredField("mSuppMatrix"); //NoSuchFieldException
f.setAccessible(true);
this.drawMatrix = new Matrix((Matrix) f.get(photoViewAttacher));
} catch (Exception e){
this.drawMatrix = null;
}

This is the way to get the suppMatrix using reflexion, then you only need to apply it in setDisplayMatrix

The getter is being added to the library, thanks a bunch

I also tried the getDisplayMatrix / setDisplayMatrix after setting a new ImageDrawable to get the same viewport and it didn't work. The problem with the code is that the getter returns the DRAW matrix (which is given to the imageView) which is the concatenation of mBaseMatrix and mSuppMatrix, while the setter only sets the mSuppMatrix which later gets multiplied by mBaseMatrix. So the mBaseMatrix gets applied many times.

In the end I fixed it in my project by adding a getSuppMatrix() method to PhotoViewAttacher and applying the result using setDisplayMatrix:

// In PhotoViewAttacher.java
public Matrix getSuppMatrix() {
    return new Matrix(mSuppMatrix);
}

// In the Fragment.java
matrixToReapply = photoViewAttacher.getSuppMatrix();
photoView.setImageDrawable(drawable);
photoViewAttacher.setDisplayMatrix(matrixToReapply);

Dude, you saved my day

Was this page helpful?
0 / 5 - 0 ratings

Related issues

imyyq-star picture imyyq-star  路  7Comments

zhangzhen92 picture zhangzhen92  路  11Comments

keeblebogdan picture keeblebogdan  路  5Comments

afollestad picture afollestad  路  7Comments

nithinpmolethu picture nithinpmolethu  路  11Comments