FrameLayout 子视图在调整大小时未正确更新

FrameLayout child view not updating correctly on resize

我有一个 Android 应用程序,其中的根视图是一个 FrameLayout,它在旋转时会保留并调整大小而不是重新创建。

FrameView 的子项中有一个自定义 View(主视图)占据了整个 space,另一个自定义 View 我想要沿底部边缘(纵向模式)或右侧边缘(横向模式)显示为窄带。

为此,我 运行 来自主视图的 onSizeChanged() 方法的以下代码:

boolean isBandShowing = ...;    // whether the band should be shown
boolean isPortrait = ...;       // whether we are in portrait mode, controls where the band is displayed
int horizontalBandHeight = ...; // default height for band in portrait mode
int verticalBandWidth = ...;    // default width for band in landscape mode

bandView.setVisibility(isBandShowing ? View.VISIBLE : View.GONE);
LayoutParams bandLayoutParams = new FrameLayout.LayoutParams(
    isPortrait ? LayoutParams.MATCH_PARENT : verticalBandWidth,  // X
    isPortrait ? horizontalBandHeight : LayoutParams.MATCH_PARENT, // Y
    Gravity.BOTTOM | Gravity.RIGHT);
bandView.setLayoutParams(bandLayoutParams);

创建后,onSizeChanged() 被调用一次(在日志输出中可见)并按预期设置 band。

然而,当显示旋转时,带的位置没有正确更新。在第一次从纵向旋转到横向后,波段仍然显示在底部。当我旋转回纵向时,乐队向右移动——它一直落后。

添加一些日志输出,我可以看到以下内容:

我尝试了一些方法,但无济于事:

什么给了?

正如我根据日志输出所怀疑的那样,在 onSizeChanged() 被调用时,UI 的内容尚未更新。我还没有弄清楚是什么,但要点是 LayoutParams 的东西需要推迟到其他一切都完成之后。这可以通过将代码包装到 Runnable 并将其 post() 发送到 FrameLayout:

来完成
static boolean isBandShowing = ...;    // whether the band should be shown
static boolean isPortrait = ...;       // whether we are in portrait mode, controls where the band is displayed
static int horizontalBandHeight = ...; // default height for band in portrait mode
static int verticalBandWidth = ...;    // default width for band in landscape mode

frameLayout.post(new Runnable() {
    @Override
    public void run() {
        bandView.setVisibility(isBandShowing ? View.VISIBLE : View.GONE);
        LayoutParams bandLayoutParams = new FrameLayout.LayoutParams(
            isPortrait ? LayoutParams.MATCH_PARENT : verticalBandWidth,  // X
            isPortrait ? horizontalBandHeight : LayoutParams.MATCH_PARENT, // Y
            Gravity.BOTTOM | Gravity.RIGHT);
        bandView.setLayoutParams(bandLayoutParams);
    }
});

那就解决了。