@@ -323,8 +323,6 @@ public Result render(boolean freshRender) {
323323 if (mViewRoot == null ) {
324324 return ERROR_NOT_INFLATED .createResult ();
325325 }
326- // measure the views
327- int w_spec , h_spec ;
328326
329327 RenderingMode renderingMode = params .getRenderingMode ();
330328
@@ -336,38 +334,64 @@ public Result render(boolean freshRender) {
336334 mMeasuredScreenHeight = params .getScreenHeight ();
337335
338336 if (renderingMode != RenderingMode .NORMAL ) {
339- // measure the full size needed by the layout.
340- w_spec = MeasureSpec .makeMeasureSpec (mMeasuredScreenWidth ,
341- renderingMode .isHorizExpand () ?
342- MeasureSpec .UNSPECIFIED // this lets us know the actual needed size
343- : MeasureSpec .EXACTLY );
344- h_spec = MeasureSpec .makeMeasureSpec (mMeasuredScreenHeight ,
345- renderingMode .isVertExpand () ?
346- MeasureSpec .UNSPECIFIED // this lets us know the actual needed size
347- : MeasureSpec .EXACTLY );
348- mViewRoot .measure (w_spec , h_spec );
349-
337+ int widthMeasureSpecMode = renderingMode .isHorizExpand () ?
338+ MeasureSpec .UNSPECIFIED // this lets us know the actual needed size
339+ : MeasureSpec .EXACTLY ;
340+ int heightMeasureSpecMode = renderingMode .isVertExpand () ?
341+ MeasureSpec .UNSPECIFIED // this lets us know the actual needed size
342+ : MeasureSpec .EXACTLY ;
343+
344+ // We used to compare the measured size of the content to the screen size but
345+ // this does not work anymore due to the 2 following issues:
346+ // - If the content is in a decor (system bar, title/action bar), the root view
347+ // will not resize even with the UNSPECIFIED because of the embedded layout.
348+ // - If there is no decor, but a dialog frame, then the dialog padding prevents
349+ // comparing the size of the content to the screen frame (as it would not
350+ // take into account the dialog padding).
351+
352+ // The solution is to first get the content size in a normal rendering, inside
353+ // the decor or the dialog padding.
354+ // Then measure only the content with UNSPECIFIED to see the size difference
355+ // and apply this to the screen size.
356+
357+ // first measure the full layout, with EXACTLY to get the size of the
358+ // content as it is inside the decor/dialog
359+ Pair <Integer , Integer > exactMeasure = measureView (
360+ mViewRoot , mContentRoot .getChildAt (0 ),
361+ mMeasuredScreenWidth , MeasureSpec .EXACTLY ,
362+ mMeasuredScreenHeight , MeasureSpec .EXACTLY );
363+
364+ // now measure the content only using UNSPECIFIED (where applicable, based on
365+ // the rendering mode). This will give us the size the content needs.
366+ Pair <Integer , Integer > result = measureView (
367+ mContentRoot , mContentRoot .getChildAt (0 ),
368+ mMeasuredScreenWidth , widthMeasureSpecMode ,
369+ mMeasuredScreenHeight , heightMeasureSpecMode );
370+
371+ // now look at the difference and add what is needed.
350372 if (renderingMode .isHorizExpand ()) {
351- int neededWidth = mViewRoot .getChildAt (0 ).getMeasuredWidth ();
352- if (neededWidth > mMeasuredScreenWidth ) {
353- mMeasuredScreenWidth = neededWidth ;
373+ int measuredWidth = exactMeasure .getFirst ();
374+ int neededWidth = result .getFirst ();
375+ if (neededWidth > measuredWidth ) {
376+ mMeasuredScreenWidth += neededWidth - measuredWidth ;
354377 }
355378 }
356379
357380 if (renderingMode .isVertExpand ()) {
358- int neededHeight = mViewRoot .getChildAt (0 ).getMeasuredHeight ();
359- if (neededHeight > mMeasuredScreenHeight ) {
360- mMeasuredScreenHeight = neededHeight ;
381+ int measuredHeight = exactMeasure .getSecond ();
382+ int neededHeight = result .getSecond ();
383+ if (neededHeight > measuredHeight ) {
384+ mMeasuredScreenHeight += neededHeight - measuredHeight ;
361385 }
362386 }
363387 }
364388 }
365389
366- // remeasure with the size we need
390+ // measure again with the size we need
367391 // This must always be done before the call to layout
368- w_spec = MeasureSpec . makeMeasureSpec ( mMeasuredScreenWidth , MeasureSpec . EXACTLY );
369- h_spec = MeasureSpec . makeMeasureSpec ( mMeasuredScreenHeight , MeasureSpec .EXACTLY );
370- mViewRoot . measure ( w_spec , h_spec );
392+ measureView ( mViewRoot , null /*measuredView*/ ,
393+ mMeasuredScreenWidth , MeasureSpec .EXACTLY ,
394+ mMeasuredScreenHeight , MeasureSpec . EXACTLY );
371395
372396 // now do the layout.
373397 mViewRoot .layout (0 , 0 , mMeasuredScreenWidth , mMeasuredScreenHeight );
@@ -444,6 +468,34 @@ public Result render(boolean freshRender) {
444468 }
445469 }
446470
471+ /**
472+ * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
473+ * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
474+ *
475+ * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
476+ * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
477+ *
478+ * @param viewToMeasure the view on which to execute measure().
479+ * @param measuredView if non null, the view to query for its measured width/height.
480+ * @param width the width to use in the MeasureSpec.
481+ * @param widthMode the MeasureSpec mode to use for the width.
482+ * @param height the height to use in the MeasureSpec.
483+ * @param heightMode the MeasureSpec mode to use for the height.
484+ * @return the measured width/height if measuredView is non-null, null otherwise.
485+ */
486+ private Pair <Integer , Integer > measureView (ViewGroup viewToMeasure , View measuredView ,
487+ int width , int widthMode , int height , int heightMode ) {
488+ int w_spec = MeasureSpec .makeMeasureSpec (width , widthMode );
489+ int h_spec = MeasureSpec .makeMeasureSpec (height , heightMode );
490+ viewToMeasure .measure (w_spec , h_spec );
491+
492+ if (measuredView != null ) {
493+ return Pair .of (measuredView .getMeasuredWidth (), measuredView .getMeasuredHeight ());
494+ }
495+
496+ return null ;
497+ }
498+
447499 /**
448500 * Insert a new child into an existing parent.
449501 * <p>
0 commit comments