自定义图像视图在棉花糖上失去状态

问题描述 投票:0回答:1

我在我的Android项目中使用PhotoView库。该项目包含SaveStatePhotoView,用于保持图像视图在配置更改(旋转,...)上的状态(缩放级别,位置)。

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

该视图在Android 7.1.1和Android 9上按预期工作。 在Android 6.0.1上,状态丢失:图像视图在设备旋转时重置为其初始状态。

我准备了一个simple project来证明这个问题。请注意,我故意使用PhotoView 1.3.1,因为我暂时不能包含传递的androidx依赖项。

android imageview orientation-changes onsaveinstancestate onrestoreinstancestate
1个回答
1
投票

N.B这似乎不是PhotoView版本2.3.0的问题。

在为API 23及以下版本重新创建时,PhotoView会经历两种布局。对于API 24+,只有一个布局通道。当有两次通过时会发生什么情况是重置onRestoreInstanceState()SaveStatePhotoView中恢复的比例(矩阵)。在您的代码中,您将在第一次传递后删除全局布局侦听器,因此,当在第二个布局传递上重置矩阵时,您没有捕获它。对于API 24+,只有一次通过,并且缩放比例已恢复且未重置。这就是为什么你看到API 23的问题而不是24的问题。

我认为真正的修复是在PhotoView中。香草ImageView也经历了两次布局传递,所以我认为额外的布局传递不是PhotoView引起的。但是,我认为PhotoView错误地处理了某些API的缩放矩阵。

您可以通过执行以下操作,在API 24+的第二次传递上设置比例来解决此问题:

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

前面的内容基于提供的运行PhotoView 1.3.1版的演示应用程序。

© www.soinside.com 2019 - 2024. All rights reserved.