Skip to content

Web UI: Layout API

Oleh edited this page Nov 7, 2019 · 21 revisions

Layout API

This page describes layouting technic for Web UI, which includes general concepts, layout examples and the use of Layout API in the Java language.

TG Flex Layout

TG Flex Layout -- it is a layout manager (similar to layout managers in Swing like Flow Layout, Mig Layout etc.). This layout manager is based on CSS Flex Box layout (more information here: A Complete Guide to Flexbox) and polymer's layout classes. TG Flex Layout also provides fluent java API to specify element placement and their styles. The layout specification looks like this:

"['center', 'start-justified', ['margin-left:20px'],[]]".

Next paragraphs explain what all this brackets and attributes means, also introduces java API that allows one to create layout specification using fluent interfaces without a need of remembering the order of brackets and attributes.

Layout Specification

Let's take a closer look at the previously mentioned layout specification:

"['center', 'start-justified', ['margin-left:20px'],[]]".

This specification consists of square brackets: [.., [], []] and attributes like: center, start-justified, margin-left:20px. Square brackets determine the containers or components and attributes define styles for container or component or some layout behaviour.

Container and components

As mentioned above square brackets in the layout specification determine the containers or components. Square brackets those have inner opening and closing brackets determine the container. The empty square brackets or square brackets with attributes determine the placeholder for a component. Each container by default layouts its inner container or a component either vertically or horizontally, which corresponds to a column or a row respectively. This layout orientation alternates, starting with vertical orientation (a column) for the outermost container. This default behaviour of the container can be changed by explicitly specifying vertical or horizontal layout attribute. For example, the following layout declares that the outermost container is a column, which consists of two rows that in turn consist of two columns.

Layout specification: "[[[],[]],[[],[]]]"

Result:

Let's change it's default layout behaviour.

Layout specification: "['horizontal',['vertical',[],[]],['vertical',[],[]]]"

Result:

Below is an image that explains the whole idea of brackets in TG Flex Layout:

Another group of mutually exclusive attributes are: start-justified, justified, end-justified, around-justified. All these four attributes define how elements are aligned along orientation axis.

start-justified - put the elements on the start of the orientation axis.

justified - distributes elements evenly along orientation axis. First element is on the start and the last element is on the end of orientation axis.

end-justified - put the elements on the end of orientation axis.

around-justified - distributes elements evenly along orientation axis with equal space around them. Hence the space between elements is twice bigger than space from the first or last element to the edge of container. See next images for better understanding.

How-Tos

This section includes (or should include) a number of useful layout examples that can be used as is or be tweaked to achieve the desired result.

3-2 layout

Flex-box can be somewhat challenging to get one's head around. It is like very much table driven, but not really: it's not possible to "insert" empty cells etc. It is best to approach layouting with flex-box as something completely new.

At its essence, tg-flex-layout is just an ordered collection of nested boxes that are either stacked horizontally or vertically. There is an outer box that can contain horizontally or vertically laid boxes, which themselves can contain other boxes etc.

Let's have a look at the 3-2 layout and how can we build it.

|------------------------------------|
| element1  |  element2  |  element3 |
|------------------------------------|
| element4  |  element5  |           |
|------------------------------------|

If one would apply the "table" logic, then it looks like that there are two rows and three columns with the right bottom cell being empty. However, in terms of the flex-box layout this is something very different. Let's try to build it incrementally.

First, we need to have a box (the main one) where the rest of the boxes would go. This main box needs to be provided with the boxes it would contain and the settings to stack them -- vertically or horizontally. In our case, we need to place two boxes (left and right) into our main box and stack them horizontally besides each other (will explain why this is the case a bit further).

Basically, we want to get the following placement of boxes:

|------------------------------------|
| |---------------| |--------------| |
| |               | |              | |
| |---------------| |--------------| |
|------------------------------------|

The following code would achieve this:

['horizontal',
   [], 
   []
 ] 

Please note that those internal two boxes are located on to different lines simply for convenience as they will be provided with extra configuration settings later.

Now let's talk why do we need those two boxes. The idea here is to use the first box (left) for placing elements 1, 2, 4 and 5 as they would fully fill that box and the second (right) box would be used to place element 3 only. Since we wanted to have all elements of the same width, it is necessary to make sure that the first box has twice the width of the second box as it should accomodate two elements horizontally, whereas the second box should accomodate only one element.

Basically, we'd like to achieve something like this:

|-----------------------------|
| |---------------| |-------| |
| |               | |       | |
| |---------------| |-------| |
|-----------------------------|

The following code does the trick:

['horizontal',
   ['flex-2'], 
   ['flex-1']
 ] 

Keywords flex-2 and flex-1 are the CSS names that are provided by Polymer (refer iron-flex-layout.html) and can be conveniently used with tg-flex-layout. These keywords are quite self-explanatory in this context -- the first box with flex-2 will occupy twice as much horizontal space (this is because their parent box has setting horizontal) as the second box. BTW keyword flex-1 has the same meaning as keyword flex and can be used interchangeably.

The next step would be to think how should each of those two boxes be filled. The first one is trickier at should hold four elements. One of the possible solutions here is to place two boxes vertically, where each box would then have other two other boxes stacked horizontally -- one box per element. Let's do this in steps.

First we place two new boxes vertically into the first box, like this:

|-----------------------------|
| |---------------| |-------| |
| | |-----------| | |       | |
| | |           | | |       | |
| | |-----------| | |       | |
| |               | |       | |
| | |-----------| | |       | |
| | |           | | |       | |
| | |-----------| | |       | |
| |---------------| |-------| |
|-----------------------------|

The following code would do what's needed:

['horizontal',
   ['flex-2', 'vertical',
      [],
      []
   ], 
   ['flex-1']
 ] 

The last thing to do in order to complete our left box, is place boxes to hold individual elements into the just added two boxes, and stack them horizontally.

|-------------------------------------------|
| |-------------------------| |-----------| |
| | |---------------------| | |           | |
| | | |-------| |-------| | | |           | |
| | | |       | |       | | | |           | |
| | | |-------| |-------| | | |           | |
| | |---------------------| | |           | |
| |                         | |           | |
| | |---------------------| | |           | |
| | | |-------| |-------| | | |           | |
| | | |       | |       | | | |           | |
| | | |-------| |-------| | | |           | |
| | |---------------------| | |-----------| |
|-------------------------------------------|

The following code would do what's needed:

['horizontal',
   ['flex-2', 'vertical',
      ['horizontal', ['flex'], ['flex']],
      ['horizontal', ['flex'], ['flex']],
   ], 
   ['flex-1']
 ] 

The above changes complete the first box. The only remaining thing is to place a box into the second box to hold element 3.

|-------------------------------------------|
| |-------------------------| |-----------| |
| | |---------------------| | |           | |
| | | |-------| |-------| | | | |-------| | |
| | | |       | |       | | | | |       | | |
| | | |-------| |-------| | | | |-------| | |
| | |---------------------| | |           | |
| |                         | |           | |
| | |---------------------| | |           | |
| | | |-------| |-------| | | |           | |
| | | |       | |       | | | |           | |
| | | |-------| |-------| | | |           | |
| | |---------------------| | |-----------| |
|-------------------------------------------|

The following achieves the final result:

['horizontal',
   ['flex-2', 'vertical',
      ['horizontal', ['flex'], ['flex']],
      ['horizontal', ['flex'], ['flex']],
   ], 
   ['flex-1', 'vertical', 
      ['flex']
   ]
 ] 

Please note that the use of setting 'margin-right: 20px' inside individual containers is desired except those that are on extreme right. This setting introduces a margin of 20px to separate elements with a bit of white space.

Clone this wiki locally