FrameLayout child view not updating correctly on resize

混江龙づ霸主 提交于 2019-12-11 11:52:30

问题


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

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).

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

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() 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:

  • 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

What gives?


回答1:


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

That solved it.



来源:https://stackoverflow.com/questions/35041691/framelayout-child-view-not-updating-correctly-on-resize

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