M Rajoy
M Rajoy

Reputation: 4084

Layout width and height being ignored

I have a dialog with a layout inside and a SurfaceTexture with a video stream. When I receive the width and height from the video, I resize my layout like this:

private void resizeView(final VideoFormatInfo info) {
        final Size size = calculateSize(info.getWidth(), info.getHeight());
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {

                final ViewGroup.LayoutParams layoutParams = mInnerLayout.getLayoutParams();
                layoutParams.width = size.x;
                layoutParams.height = size.y;
                Log.i(TAG, String.format("run: setting innerlayout bounds to %d,%d", size.x, size.y));
                mInnerLayout.setLayoutParams(layoutParams);
            }
        });
    }

Now I have a fullscreen button that is supposed to resize the layout to the whole screen. But when I press it, the layout remains in a small area of the screen.

When I check the log the proper value on size.x and size.y is there (the bounds of the screen), yet the layout is not properly resized.

The innerlayout is added to a customView named "VideoPlayer". I set the color of the videoplayer background to red so when I switch to fullscreen the whole screen turns red, except for the video stream in the middle. This means that the underlying view is being properly resized but the innerLayout is not for some reason.

Funny thing is, I have another layout over the video render that creates a "flash effect" to simulate a camera flash when taking a snapshot. When that flash effect is triggered, then the video is resized to the whole screen.

So this is my layout tree:

VideoPlayerView (CustomView, not VideoView)
     innerLayout (RelativeLayout)
         videoSurfaceTexture (SurfaceTextureView)
         flashLayout (RelativeLayout)

I also set this for debugging:

 @Override
            public void onSurfaceTextureSizeChanged(final SurfaceTexture surfaceTexture, final int width, final int height) {
                Log.d(TAG, "onSurfaceTextureSizeChanged size=" + width + "x" + height + ", st=" + surfaceTexture);

                Log.i(TAG, String.format("innerlayout bounds are %d,%d", mInnerLayout.getLayoutParams().width, mInnerLayout.getLayoutParams().height));
            }

And the values on the inner layout are the proper values (those of the whole screen) when I press fullscreen, but the layout is not resized. I can tell it's the layout not being resized because I changed its background color to green and added some padding and I can see it in the center of screen taking a small space.

It looks as though somehow the view is not being updated with the layout changes.

I am running out of ideas here. I tried invalidate(), postInvalidate() and forceLayout() but those dont work.

Upvotes: 6

Views: 1773

Answers (3)

Elltz
Elltz

Reputation: 10859

final ViewGroup.LayoutParams layoutParams = mInnerLayout.getLayoutParams();
layoutParams.width = size.x;
layoutParams.height = size.y;
Log.i(TAG, String.format("run: setting innerlayout bounds to %d,%d", size.x, size.y));
 ViewGroup parent = ((ViewGroup)mInnerLayout.getParent());
 parent.removeView(mInnerLayout);
 mInnerLayout.setLayoutParams(layoutParams);
 parent.addView(mInnerLayout);//you might need to get the index so you slot it in there.

This will do. -(all thoughts)

EDIT

i didnt want to add explanation because it was all thoughts and i needed verifying if it will work

But the explanation for my code is LayoutParams are what the Parent uses to layout its children hence it is useful only in the laying out pulse or time. Changing the layoutParams object makes the View object dirty, other factors need to be met before a dirty View is layed out, so that is why the values change but the View is not changed.

you could have also just called View.invalidate() and View.requestLayout() on that particular View or Parent and it will also solve your problem, calling View.invalidate() alone will not do instantly for you. eg

layoutParams.width = size.x;
layoutParams.height = size.y;
Log.i(TAG, String.format("run: setting innerlayout bounds to %d,%d", size.x, size.y));
//re-setting the layout params is also not neccessary
mInnerLayout.invalidate();
mInnerLayout.requestLayout();    

The reason the first approach solves your problem is because the View is remove and added which calls for a Laying out to be processed

:) also you should have just accepted it and let the bounty period elapsed :)

Upvotes: 2

tynn
tynn

Reputation: 39843

You missed one important part of forceLayout():

This method does not call requestLayout() or forceLayout() on the parent.

So make the parent do a layout as well:

mInnerLayout.setLayoutParams(layoutParams);
mInnerLayout.forceLayout();
mInnerLayout.getParent().requestLayout();

Upvotes: 4

Masroor_Shah
Masroor_Shah

Reputation: 313

use Inflator like

View view = inflater.inflate( R.layout.item /* resource id */,
                                         MyView.this /* parent */,
                                         false /*attachToRoot*/);

for more check Layout params of loaded view are ignored

Upvotes: 1

Related Questions