Layout managers are installed on the Container class and effectively position the Components within the given container. The LayoutManager class is abstract and allows users to create their own layout managers, however Codename One ships with multiple layout managers allowing for the creation of many layout types.
The layout managers are designed to allow developers to build user interfaces that seamlessly adapt to all resolutions and thus they don’t state the component size/position but rather the intended layout behavior. To install a layout manager one does something like this:
Container c = new Container(new BoxLayout(BoxLayout.X_AXIS));
c.addComponent(new Button("1"));
c.addComponent(new Button("2"));
c.addComponent(new Button("3"));
This would produce 3 buttons one next to the other horizontally.
There are two major types of layout managers: Constraint based & regular. The regular layout managers like the box layout are just installed on the container and “do their job”. The constraint based layout managers associate a value with a Component sometimes explicitly and sometimes implicitly. Codename One ships with 3 such layouts BorderLayout, TableLayout & GroupLayout.
A constraint layout can/must accept a value when adding the component to indicate its position e.g.:
Container c = new Container(new BorderLayout());
c.addComponent(BorderLayout.CENTER, new Button("1"));
c.addComponent(BorderLayout.NORTH, new Button("2"));
c.addComponent(BorderLayout.SOUTH, new Button("3"));
This will stretch button 1 across the center of the container and buttons 2-3 will be stretched horizontally at the top and bottom of the container. Notice that the order to adding doesn’t mean much once we have a constraint involved...
Flow Layout
Flow layout can be used to just let the components “flow” horizontally and break a line when reaching the end of the component. It is the default layout manager for Codename One but because it is so flexible it could be problematic since it can cause the preferred size of the Container to provide false information triggering endless layout reflows (see below).Flow layout can be aligned to the left (by default) center or to the right. Components within the flow layout get their natural preferred size by default and are not stretched in any axis.
The layout manager also supports modifying the horizontal alignment of the flow layout in cases where the container grows vertically.
final Container layouts = new Container(); final Button borderLayout = new Button("Border");
final Button boxYLayout = new Button("Box Y");
final Button boxXLayout = new Button("Box X");
final Button flowLayout = new Button("Flow");
final Button flowCenterLayout = new Button("Flow Center");
final Button gridLayout = new Button("Grid");
final Button tableLayout = new Button("Table");
layouts.setLayout(new FlowLayout(Component.CENTER));
layouts.addComponent(borderLayout);
layouts.addComponent(boxYLayout);
layouts.addComponent(boxXLayout);
layouts.addComponent(flowLayout);
layouts.addComponent(flowCenterLayout);
layouts.addComponent(gridLayout);
layouts.addComponent(tableLayout);
Box Layout
Box layout allows placing components in a horizontal or a vertical line that doesn’t break the line. Components are stretched along the opposite axis, e.g. X axis box will flow components horizontally and stretch them vertically..
Box layout accepts the axis in its constructor, the axis can be either BoxLayout.X_AXIS or BoxLayout.Y_AXIS.
Border Layout
Border layout is quite unique, its a constraint based layout that can place up to 5 components in one of the 5 positions: North, South, East, West or Center.
The layout always stretches the North/South components on the X axis to completely fill the container and the East/West components on the Y axis. The center component is stretched to fill the remaining area by default. However, the border layout has a flag to manipulate the behavior of the center component allowing it to be placed in the absolute center without stretching.
Grid Layout
The Grid Layout accepts a predefined grid rows/columns and grants all components within it an equal size based on the dimensions of the largest component. It is an excellent layout for a set of icons in a grid.
It can also dynamically calculate the columns/rows based on available space.
Table Layout
The table layout is far more elaborate than the grid layout and more akin to the HTML table structure. It is a constraint based layout, however it includes a default constraint if none are specified (e.g. using addComponent(cmp) is equivalent to using addComponent((layout.createConstraint(), cmp)).A table generally gives elements their preferred sizes but stretches them based on column/row. There are abilities within the constraint element to define multiple behaviors such as row/column spanning, alignments and grow behavior.
Layered Layout
The layered layout just places the components in order one on top of the other and sizes them all to the size of the largest component. This is useful when trying to create an overlay on top of an existing component e.g. an “x” button to allow removing the component.Understanding Preferred Size
The component class contains many useful methods, one of the most important ones is calcPreferredSize() which is invoked to recalculate the size a component “wants” when something changes (by default Codename One calls getPreferredSize() which caches the value).The preferred size is decided by the component based on many constraints such as the font size, border sizes, padding etc. When a layout places the component it will size it based on its preferred size or ignore its preferred size either entirely or partially. Eg. FlowLayout always gives components their exact preferred size yet BorderLayout resizes the center component by default (and the other components on one of their axis).
Layout Reflow
When adding a component to a form which isn’t shown on the screen there is no need to tell the UI to repaint or reflow. This happens implicitly. However, when adding a component to a UI which is already visible the component will not show by default.The reason for this is performance based. E.g. imagine adding 100 components to an already visible form with 100 components within it. If we laid out automatically layout would have happened 100 times when it can happen only once.
That is why when you add components to a form that is already showing you should invoke revalidate or animate the layout appropriately. This also enables the layout animation behavior.
0 comments:
Post a Comment