FrameLayout子视图在调整大小时无法正确更新 [英] FrameLayout child view not updating correctly on resize

查看:375
本文介绍了FrameLayout子视图在调整大小时无法正确更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an Android application in which the root view is a FrameLayout which on rotation is kept and resized rather than recreated.

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

Among the children of the FrameView is one custom View (the main view) that takes up the entire space, and another custom View which I want to display as a narrow band along the bottom edge (in portrait mode) or the right edge (in landscape mode).

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

To this end I run the following code from the main view's onSizeChanged() method:

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()被调用一次(在日志输出中可见)并按预期方式设置频段.

Upon creation, onSizeChanged() gets called once (visible in the log output) and sets up the band as it is supposed to.

但是,旋转显示器时,波段的位置未正确更新.从肖像到风景的第一次旋转后,乐队仍显示在底部.当我旋转回肖像时,乐队会向右移动-一直落后.

When the display is rotated, however, the position of the band is not updated properly. After the first rotation from portrait into landscape, the band still displays at the bottom. When I rotate back into portrait, the band moves to the right – it is consistently lagging behind.

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

Adding some log output, I can see the following:

  • onSizeChanged()每次旋转都会被调用
  • 顶部的四个变量具有正确的值(人像/风景正确反映了新的方向)
  • 如果我从新创建的LayoutParams中查询宽度和高度,则它们具有预期值
  • 如果我在调用setLayoutParams()之后立即查询bandView的尺寸,则它们具有旧值(如旋转之前显示的那样).
  • onSizeChanged() gets called on every rotation
  • the four variables at the top have the correct value (portrait/landscape correctly reflects the new orientation)
  • if I query the width and height from the newly created LayoutParams, they have the expected values
  • if I query the dimensions of bandView right after the call to setLayoutParams(), they have the old values (as displayed before the rotation).

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

I've tried a few things, to no avail:

  • FrameLayout和波段视图上同时调用requestLayout()
  • 同时调用invalidate()
  • 同时调用postInvalidate()
  • 在设置新的LayoutParams之前先从FrameLayout中删除bandView,然后重新添加
  • calling requestLayout() on both the FrameLayout and the band view
  • calling invalidate() on both
  • calling postInvalidate() on both
  • removing bandView from the FrameLayout before setting the new LayoutParams, then re-adding it

有什么作用?

推荐答案

正如我根据日志输出所怀疑的那样,在调用onSizeChanged()时,UI胆量尚未更新.我还没有弄清楚是什么,但是要点是,LayoutParams的内容需要推迟到其他所有内容都完成之后再进行.可以通过将代码包装到Runnable并将其post()封装到FrameLayout中来完成:

As I had suspected based on the log output, something in the guts of the UI has not been updated by the time onSizeChanged() gets called. I haven't figured out what, but the takeaway is that the LayoutParams stuff needs to be deferred until everything else has finished. This can be done by wrapping the code into a Runnable and post()ing that to the 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);
    }
});

那解决了.

这篇关于FrameLayout子视图在调整大小时无法正确更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆