User interface has to be adjustable and adaptive to an environment and a hardware where it can be shown. In that respect existence of mobile phones, various WEB browsers, different operation systems, PCs, laptops, tablets and combinations of all these factors makes life harder. To avoid potential UI layouting problems developers should not locate and size UI components by assigning dedicated (x,y) coordinates and (width,height) values. Otherwise even slight font changing can crash designed UI layout.
Layout managers is well known solution to get adaptive UI. That is exactly the thing 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 is defined on the level of an UI component and “knows” two important things:
How to order UI children components
How to compute the component preferred size basing on its children components hierarchy
Technically zbkit layout manager class has to implement the following:
“doLayout(target)” method to define rules children components of the given target component has to be laid outed
“calcPreferredSize(target)” method to calculate size the given target component desires to have
“zebkit.layout.Layout” interface should be implemented by a layout manager class
A layout manager can be applied to any Zebra UI component by calling “setLayout(layout)” method. Additionally children UI components can specify extra parameter called constraints that is specific for a particular layout manager. It is can be done either by setting a children component “constraints” field or during insertion of the component to the parent component:
zebkit.require("ui", function(ui) {
// create panel
var p = new ui.Panel();
// set layout manager for the panel
p.setBorderLayout();
// add children components
p.add("center", new ui.Label("Center"));
// another way to specify constraints is filling "constraints"
// field of a children component
var l = new ui.Label("Top");
l.constraints = "top";
p.add(l);
...
});
Nevertheless zebkit provides rich set of different predefined layout managers, it makes sense for better understanding to start from developing an own Zebra layout manager. It should help to discover how simple the idea is. As an example, 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,[
// define what preferred size the given "target" component
// wants to have. in this case it calculated as sum of
// preferred heights and widths of children 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 children 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 just developed diagonal layout manager as follow:
Custom diagonal layout |
zebkit.require("ui", "ui.demo", function(ui, demo) {
var r = new ui.zCanvas("layoutSampleDiag", 200,200).root;
// 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"));
});
Below you can find snapshots for all supplied by zebkit layout managers. Every snapshots are provided together with “live” application that run the snapshot source code directly on this page.
The layout manager places children UI components over each other and stretches its to fill the whole parent component surface.
Paint on top method implementation |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("layoutSample1", 300, 300).root;
r.setBorder("plain");
// set stack layout manager
r.setStackLayout();
// add button
r.add(new ui.Button("Under transparent"));
// add partially transparent panel component
var p = new ui.Panel();
p.setBackground("rgba(240,240,240,0.7)");
r.add(p);
});
Border layout manager splits component area into five parts: top, left, right, bottom and center. Children components are placed to one of the part basing on constraints that have been specified for them:
Border layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("layoutSampleBorder", 600,350).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"));
});
Percent layout manager orders children components basing on percentage sizes of the components. The percentage sizes are defined as the children components constraints.
Horizontally ordered percent layout manager with stretched vertically components
Percent layout |
zebkit.require("ui","layout",function(ui, lay) {
var r = new ui.zCanvas("percentLayout1", 400, 250).root;
r.setBorder("plain");
// 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%"));
});
Horizontally ordered percent layout manager with preferred components heights
Percent layout |
zebkit.require("ui","layout",function(ui, lay) {
var r = new ui.zCanvas("percentLayout2", 400, 200).root;
r.setBorder("plain");
// set percent layout manager that sizes components vertically
// according to its preferred heights and sizes components
// horizontally according to its percentage constraints
r.setLayout(new lay.PercentLayout("horizontal", 2, false));
// 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%"));
});
Vertically ordered percent layout manager with preferred components widths
Percent layout |
zebkit.require("ui","layout",function(ui, lay) {
var r = new ui.zCanvas("percentLayout3", 400,200).root;
r.setBorder("plain");
// set percent layout manager that sizes components horizontally
// according to its preferred widths and sizes components
// vertically according to its percentage constraints
r.setLayout(new lay.PercentLayout("vertical", 2, false));
// add button that takes 20% of vertical space
r.add(20, new ui.Button("20%"));
// add button that takes 30% of vertical space
r.add(30, new ui.Button("30%"));
// add button that takes 50% of vertical space
r.add(50, new ui.Button("50%"));
});
Vertically ordered percent layout manager with stretched horizontally components
Percent layout |
zebkit.require("ui","layout",function(ui, lay) {
var r = new ui.zCanvas("percentLayout4", 400,200).root;
r.setBorder("plain");
// set percent layout manager that stretches components
// horizontally and sizes components vertically according
// to its percentage constraints
r.setLayout(new lay.PercentLayout("vertical", 2, true));
// add button that takes 20% of vertical space
r.add(20, new ui.Button("20%"));
// add button that takes 30% of vertical space
r.add(30, new ui.Button("30%"));
// add button that takes 50% of vertical space
r.add(50, new ui.Button("50%"));
});
Flow layout provides many possibilities to align children components.
Vertically ordered UI components are centered horizontally and vertically:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout1", 400, 200).root;
r.setBorder("plain");
// set flow layout with vertical components ordering and center
// vertical and horizontal alignments
r.setFlowLayout("center","center","vertical",2);
// add children components
r.add(new ui.Button("VCentered"));
r.add(new ui.Button("VCentered"));
r.add(new ui.Button("VCentered"));
});
Vertically ordered UI components are aligned top-left:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout2", 400,200).root;
r.setBorder("plain");
// set flow layout with vertical components
// ordering, top-left alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("left","top","vertical", 2);
// add children components
r.add(new ui.Button("Left-Top-Ver"));
r.add(new ui.Button("Left-Top-Ver"));
r.add(new ui.Button("Left-Top-Ver"));
});
Vertically ordered UI components are aligned top-right:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout3", 400,200).root;
r.setBorder("plain");
// set flow layout with vertical components
// ordering, top-right alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("right","top","vertical", 2));
// add children components
r.add(new ui.Button("Right-Top-Ver"));
r.add(new ui.Button("Right-Top-Ver"));
r.add(new ui.Button("Right-Top-Ver"));
});
Vertically ordered UI components are aligned bottom-right:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout4", 200,200).root;
r.setBorder("plain");
// set flow layout with vertical components
// ordering, bottom-right alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("right","bottom", "vertical", 2);
// add children components
r.add(new ui.Button("Right-Bottom-Ver"));
r.add(new ui.Button("Right-Bottom-Ver"));
r.add(new ui.Button("Right-Bottom-Ver"));
});
Horizontally ordered UI components are centered vertically and horizontally:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout5", 600,120).root;
r.setBorder("plain");
// set flow layout with horizontal components
// ordering, center-center alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("center","center","horizontal", 2);
// add children components
r.add(new ui.Button("HCentered"));
r.add(new ui.Button("HCentered"));
r.add(new ui.Button("HCentered"));
});
Horizontally ordered UI components are aligned center-left:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout6", 600,120).root;
r.setBorder("plain");
// set flow layout with horizontal components
// ordering, center-left alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("left","center","horizontal",2);
// add children components
r.add(new ui.Button("Left-Center-Hor"));
r.add(new ui.Button("Left-Center-Hor"));
r.add(new ui.Button("Left-Center-Hor"));
});
Horizontally ordered UI components are aligned center-right:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout7", 600,120).root;
r.setBorder("plain");
// set flow layout with horizontal components
// ordering, center-right alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("right","center","horizontal", 2);
// add children components
r.add(new ui.Button("Right-Center-Hor"));
r.add(new ui.Button("Right-Center-Hor"));
r.add(new ui.Button("Right-Center-Hor"));
});
Horizontally ordered UI components are aligned top-right:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout8", 600,120).root;
r.setBorder("plain");
// set flow layout with horizontal components
// ordering, top-right alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("right","top","horizontal", 2));
// add children components
r.add(new ui.Button("Right-Top-Hor"));
r.add(new ui.Button("Right-Top-Hor"));
r.add(new ui.Button("Right-Top-Hor"));
});
Horizontally ordered UI components are aligned top-left:
Flow layout |
zebkit.require("ui", function(ui) {
var r = new ui.zCanvas("flowLayout9", 600,120).root;
r.setBorder("plain");
// set flow layout with horizontal components
// ordering, top-left alignment and 2 pixels
// gap between inserted components
r.setFlowLayout("left","top","horizontal",2);
// add children components
r.add(new ui.Button("Left-Top-Hor"));
r.add(new ui.Button("Left-Top-Hor"));
r.add(new ui.Button("Left-Top-Hor"));
});
Raster layout manager is default Zebra component layout manager. It emulates the standard approach where locations and sizes are precisely specified by calling “setLocation(x,y)”, “setSize(w,h)” or “setBounds(x,y,w,h)” methods. It is strongly recommended to avoid using raster layout manager the way developers define exact values for a component location and size. Rules are better in respect of implementing adaptive UI that doesn’t depend on screen resolutions, font metrics, allocated for an UI application size and so on.
Hardcoded, user defined components locations and sizes:
Raster layout |
Raster layout manager also can be less dependent from an environment an UI application can be run:
Size components to its referred size:
Raster layout |
Size components to its preferred size and align its:
Raster layout |
List layout manager orders children component vertically as a list of items.
Children components are stretched horizontally to occupy whole parent container width:
Raster layout |
Children components are centered horizontally:
List layout |
Children components are aligned left:
List layout |
Grid layout manager splits a component area to number of virtual cells. Children components are placed into the cells. One cell can be occupied only by one children component. Using “zebkit.layout.Constraints” class developers can control how a children component has to be placed inside the virtual cell. “zebra.layout.Constraints” declares the following fields that declares how a component has to be placed inside a virtual cell:
Field | Allowed values | Description |
---|---|---|
ax |
"left" "right" "center" "stretch" | Horizontal alignment in cell |
ay |
"top" "bottom" "center" "stretch" | Vertical alignment in cell |
top,left, bottom,right | integer value >= 0 | Cell top, left, bottom and right paddings |
The picture below explains how a component can be aligned inside a virtual cell controlled by grid layout manager:
Default grid layout manager constraints
List layout |
1. Custom grid layout manager constraints
List layout |
2. Custom grid layout manager constraints
List layout |
All zebra layout managers are hosted in “zebra.layout” package. The package provides the core “zebra.layout.Layoutable” class. This class describes a rectangular object that is bound with the given size and location. “zebra.layout.Layoutable” component can contain other layoutable components as its children. The children components are laid outed with a layout manager. Pay attention “zebra.layout” package is completely independent from UI part. Developer can easily use it as basis for layout management, for instance, for WEB based elements. Zebra UI engine just extends the basic “zebra.layout.Layoutable” class with visual and event related stuff.
The package provides number of useful API methods that can be handy to manipulate with component hierarchy:
API method | Description |
---|---|
zebra.layout.getDirectChild(p,k) | get immediate kid for the given parent and children component |
zebra.layout.getDirectAt(x,y,p) | get immediate kid located at the given location of the specified parent component |
Also it declares number of constants that from time to time have to be used as a layout constraints:
[wpcol_2third]
[table]
Constraints;Description
“left”; left constraint or alignment
“right”; right constraint or alignment
“top”; top constraint or alignment
zebra.layout.BOTTOM; bottom constraint or alignment
“center”; center constraint or alignment
“horizontal”; horizontal constraint or alignment
“vertical”; vertical constraint or alignment
zebra.layout.STRETCH; stretch constraint
zebra.layout.USE_PS_SIZE; use preferred size
zebra.layout.TLEFT; top left constraint or alignment
zebra.layout.TRIGHT; top right constraint or alignment
zebra.layout.BLEFT; bottom left constraint or alignment
zebra.layout.BRIGHT; bottom right constraint or alignment
[/table][/wpcol_2third][wpcol_1third_end]
[/wpcol_1third_end]