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()
每次轮换都会被调用
- 顶部的四个变量具有正确的值(portrait/landscape 正确反映了新方向)
- 如果我从新创建的
LayoutParams
查询宽度和高度,它们具有预期值
- 如果我在调用
setLayoutParams()
后立即查询 bandView
的维度,它们具有旧值(如旋转前显示的那样)。
我尝试了一些方法,但无济于事:
- 在
FrameLayout
和 band 视图中调用 requestLayout()
- 两者都调用
invalidate()
- 两者都调用
postInvalidate()
- 在设置新的
LayoutParams
之前从 FrameLayout
中删除 bandView
,然后重新添加
什么给了?
正如我根据日志输出所怀疑的那样,在 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);
}
});
那就解决了。
我有一个 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()
每次轮换都会被调用- 顶部的四个变量具有正确的值(portrait/landscape 正确反映了新方向)
- 如果我从新创建的
LayoutParams
查询宽度和高度,它们具有预期值 - 如果我在调用
setLayoutParams()
后立即查询bandView
的维度,它们具有旧值(如旋转前显示的那样)。
我尝试了一些方法,但无济于事:
- 在
FrameLayout
和 band 视图中调用requestLayout()
- 两者都调用
invalidate()
- 两者都调用
postInvalidate()
- 在设置新的
LayoutParams
之前从FrameLayout
中删除bandView
,然后重新添加
什么给了?
正如我根据日志输出所怀疑的那样,在 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);
}
});
那就解决了。