问题
I am using the PhotoView library in my Android project. The project contains the SaveStatePhotoView which is used to keep the state (zoom level, position) of the image view on configuration changes (rotation, ...).
// SaveStatePhotoView.java
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
final SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
restoreSavedState(ss);
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
}
The view works as desired on Android 7.1.1 and Android 9.
On Android 6.0.1 the state is lost: the image view resets to its initial state when the device is rotated.
I prepared a simple project to demonstrate the issue. Please note that I am using PhotoView 1.3.1 on purpose because I cannot include transitive androidx
dependencies at the moment.
回答1:
N.B This does not seem to be an issue with PhotoView version 2.3.0.
PhotoView undergoes two layouts when recreated for API 23 and under. For API 24+, there is only one layout pass. What happens when there are two passes is that the scale (a matrix) that is restored in onRestoreInstanceState()
of SaveStatePhotoView
is reset. In your code, you are removing the global layout listener after the first pass so, when the matrix is reset on the second layout pass, you are not catching it. For API 24+, there is only one pass and the scale is restored and not reset. This is why you see an issue for API 23 and not for 24.
I think that the real fix is in PhotoView. A vanilla ImageView
also undergoes two layout passes, so I don't think the extra layout pass is something that PhotoView causes. I do think, however, that PhotoView mishandles the scaling matrix for certain APIs.
You can address this issue by setting the scale on the second pass for API 24+ by doing something like this:
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
final SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private int invocationCount = 0;
// Only one layout pass for M and up. Otherwise, we'll see two and the
// scale set in the first pass is reset during the second pass, so the scale we
// set doesn't stick until the 2nd pass.
@Override
public void onGlobalLayout() {
setScale(Math.min(ss.scale, getMaximumScale()), getWidth() * ss.pivotX,
getHeight() * ss.pivotY, false);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M || ++invocationCount > 1) {
getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
}
The preceding is based upon the supplied demo app running PhotoView version 1.3.1.
来源:https://stackoverflow.com/questions/55087954/custom-image-view-looses-state-on-marshmallow