Custom image view looses state on Marshmallow

走远了吗. 提交于 2019-12-08 10:44:37

问题


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

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