By Duncan Mills on Oct 25, 2012
A classic layout conundrum, which I think pretty much every ADF developer may have faced at some time or other, is that of truly centered (centred) layout. Typically this requirement comes up in relation to say displaying a login type screen or similar.
Superficially the problem seems easy, but as my buddy Eduardo explained when discussing this subject a couple of years ago it's actually a little more complex than you might have thought. If fact, even the "solution" provided in that posting is not perfect and suffers from a several issues (not Eduardo's fault, just limitations of panelStretch!)
- The top, bottom, end and start facets all need something in them
- The percentages you apply to the topHeight, startWidth etc. are calculated as part of the whole width. This means that you have to guestimate the correct percentage based on your typical screen size and the sizing of the centered content. So, at best, you will in fact only get approximate centering, and the more you tune that centering for a particular browser size the more it will fail if the user resizes.
- You can't attach styles to the panelStretchLayout facets so to provide things like background color or fixed sizing you need to embed another container that you can apply styles to, typically a panelgroupLayout
For reference here's the code to print a simple 100px x 100px red centered square using the panelStretchLayout solution, approximately tuned to a 1980 x 1080 maximized browser (IDs omitted for brevity):
<af:panelStretchLayout startWidth="45%" endWidth="45%" topHeight="45%" bottomHeight="45%" > <f:facet name="center"> <af:panelGroupLayout inlineStyle="height:100px;width:100px;background-color:red;" layout="vertical"/> </f:facet> <f:facet name="top"> <af:spacer height="1" width="1"/> </f:facet> <f:facet name="bottom"> <af:spacer height="1" width="1"/> </f:facet> <f:facet name="start"> <af:spacer height="1" width="1"/> </f:facet> <f:facet name="end"> <af:spacer height="1" width="1"/> </f:facet> </af:panelStretchLayout>
And so to panelGridLayout
So here's the good news, panelGridLayout makes this really easy and it works without the caveats above. The key point is that percentages used in the grid definition are evaluated after the fixed sizes are taken into account, so rather than having to guestimate what percentage will "more, or less", center the content you can just say "allocate half of what's left" to the flexible content and you're done.
Here's the same example using panelGridLayout:
<af:panelGridLayout> <af:gridRow height="50%"/> <af:gridRow height="100px"> <af:gridCell width="50%" /> <af:gridCell width="100px" halign="stretch" valign="stretch" inlineStyle="background-color:red;"> <af:spacer width="1" height="1"/> </af:gridCell> <af:gridCell width="50%" /> </af:gridRow> <af:gridRow height="50%"/> </af:panelGridLayout>
So you can see that the amount of markup is somewhat smaller (as is, I should mention, the generated DOM structure in the browser), mainly because we don't need to introduce artificial components to ensure that facets are actually observed in the final result. But the key thing here is that the centering is no longer approximate and it will work as expected as the user resizes the browser screen. By far this is a more satisfactory solution and although it's only a simple example, it will hopefully open your eyes to the potential of panelGridLayout as your number one, go-to layout container.
Just a reminder though, right now, panelGridLayout is only available in 18.104.22.168 and above.