User interface has to be adaptive to an environment and a hardware where it can be shown. To avoid potential UI layouting problems developers should not positioning and sizing UI components by assigning dedicated (x,y) coordinates and (width,height) size.
Layout managers is well known solution to get adaptive UI that helps developing adjustable UI layout. Layout manager doesn’t trust fixed UI components positions and sizes. It uses rules-based manner to order UI components. Layout manager “knows” two important things:
Usage layout manager in zebkit looks something like the following:
zebkit.require("ui", function(ui) {
...
var pan = new ui.Panel();
// Set layout manager for the container
pan.setBorderLayout();
...
// Border layout manager orders child components
// with number of predefined alignments (top, center, left,
// etc). Let's add a component at the top of panel
pan.add("top", new ui.Button("Ok"));
...
});
Zebkit is supplied with a number ready-to-use layout managers. In most cases they are enough for building UI application.
The layout manager orders child components basing on its exact locations and sizes that are set via “setLocation(x, y)”, “setSize(w,h)” or “setBounds(x, y, w, h)” methods. But also the manager can use preferred sizes and custom vertical and horizontal alignments to place the child components.
Raster layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas().root;
// raster layout that size components according to
// its preferred size
r.setRasterLayout(true);
// add children UI components with different constraints
r.add("center", new ui.Button("Center,\npreferred Sized"));
r.add("bottomLeft",new ui.Button("BottomLeft,\npreferred sized"));
r.add("topRight",new ui.Button("TopRight,\npreferred sized"));
});
This the most simple layout manager that place child components on top of each other stretching (or using preferred size) its to fill all available parent component space.
Stack layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas().root;
// setup stack layout
r.setStackLayout();
// add child component stretched vertically and
// horizontally over the whole parent component area
r.add(new ui.Button("Stretched\n\n\n\n button"));
// add child component sized according its
// preferred size
r.add("usePsSize", new ui.Button("Ok"));
});
The layout manager splits container area into five logical areas: “left”, “right”, “top”, “bottom”, “center”. Child components can be added to occupy one of the listed above logical area:
Border layout |
zebkit.require("ui",function(ui) {
var r = new ui.zCanvas().root;
// set border layout manager
r.setBorderLayout();
// add children UI components with different constraints
r.add("center", new ui.Button("CENTER"));
r.add("left", new ui.Button("LEFT"));
r.add("right", new ui.Button("RIGHT"));
r.add("top", new ui.Button("TOP"));
r.add("bottom", new ui.Button("BOTTOM"));
});
List layout manager treats child components as sequence of list items ordered vertically. The items can be either aligned horizontally or stretched to occupy the whole available horizontal space.
List layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas().root;
// set list layout manager that orders components as list
// items and stretches child components horizontally
r.setListLayout();
// add child components
r.add(new ui.Button("Stretched Item 1"));
r.add(new ui.Button("Stretched Item 1"));
r.add(new ui.Button("Stretched Item 1"));
});
This layout manager orders child components vertically or horizontally according to specified as constraints height or width. Height and width are specified in percents.
Percentage layout |
zebkit.require("ui","layout",function(ui, lay) {
var r = new ui.zCanvas().root;
// set percent layout manager that stretches components
// vertically and sizes component horizontally according
// to its percentage constraints
r.setLayout(new lay.PercentLayout());
// add button that takes 20% of horizontal space
r.add(20, new ui.Button("20%"));
// add button that takes 30% of horizontal space
r.add(30, new ui.Button("30%"));
// add button that takes 50% of horizontal space
r.add(50, new ui.Button("50%"));
});
Flow layout manager orders child components vertically or horizontally according to its preferred size. Depending of a selected child components ordering (vertical or horizontal) they can be aligned “top”, “bottom”, “center” or “left”, “right”, “center”.
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas().root;
// set flow layout with vertical components ordering and center
// vertical and horizontal alignments
r.setFlowLayout("center", "center", "vertical", 2);
// add child components
r.add(new ui.Button("VCentered"));
r.add(new ui.Button("VCentered"));
r.add(new ui.Button("VCentered"));
});
Grid layout splits container area to number of logical cells where child components have to be placed. Every child component can have specified constraints that says how the component has to be aligned inside the virtual cell (vertical alignment, horizontal alignment, stretching).
Grid layout |
zebkit.require("ui","layout", function(ui, layout) {
var r = new ui.zCanvas().root;
// create layout that splits a container area
// into four virtual cells (2 rows, and 2 columns)
r.setLayout(new layout.GridLayout(2,2));
// add child components
r.add(new ui.Button("1x1"));
r.add(new ui.Button("1x2"));
r.add(new ui.Button("2x1"));
r.add(new ui.Button("2x2"));
});
If existent layout managers are not enough it is not a big deal to implement a custom one. To do it inherit “zebkit.layout.Layout” interface and implement the following two methods:
Let’s develop layout manager that orders components along parent component diagonal:
zebkit.package("ui.demo", function(pkg, Class) {
// declare layout manager class
pkg.DiagLayout = Class(zebkit.layout.Layout,[
// preferred size target component wants to have is calculated
// as sum of preferred sizes of child components
function calcPreferredSize(target) {
var psW = 0, psH = 0;
for(var i=0; i < target.kids.length; i++) {
var kid = target.kids[i];
if (kid.isVisible) {
var ps = kid.getPreferredSize();
psW += ps.width;
psH += ps.height;
}
}
return { width:psW, height:psH };
},
// define rules how child components of the
// given "target" have to be ordered
function doLayout(target) {
var x = target.getTop(), y = target.getLeft();
for(var i=0; i < target.kids.length; i++) {
var kid = target.kids[i];
if (kid.isVisible) {
var ps = kid.getPreferredSize();
kid.setBounds(x, y, ps.width, ps.height);
x += ps.width;
y += ps.height;
}
}
}
]);
});
Use the developed diagonal layout manager as follow:
Custom diagonal layout |
zebkit.require("ui", "ui.demo", function(ui, demo) {
var r = new ui.zCanvas().root;
r.setPadding(8);
r.setBorder("plain");
// set developed above diagonal layout manager
r.setLayout(new demo.DiagLayout());
// add children components
r.add(new ui.Button("One ..."));
r.add(new ui.Button("Two ..."));
r.add(new ui.Button("Three ..."));
});