Skip to content

Commit 8a18dba

Browse files
author
Xavier Ducrohet
committed
Merge c5aeac7 from honeycomb.
LayoutLib: Fix issue with rendering mode. When the layout content is embedded inside a decor layout to emulate system bar (top or bottom) and title bar (or action bar) then the code computing the full required size based on the RenderingMode would fail because the decor layout would prevents the content layout to take as much room as possible. There is also an issue with the way we know render dialogs as the dialogs usually as a frame with some padding and the previous measurements would not take into account the dialog padding when increasing the screen size. This fix makes the code measure the size of the content layout in the normal rendering, and then separately from the root layout with the proper MeasureSpec to let the content grown. The difference in size is then added to the screen size. Bug: http://code.google.com/p/android/issues/detail?id=15892 Change-Id: Ie9a6c5e254b16785f817dcb9fae755d4936880aa
1 parent 43707a8 commit 8a18dba

File tree

1 file changed

+75
-23
lines changed

1 file changed

+75
-23
lines changed

tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)