Stop Hard-Coding Pixels: Using Flex Layout in Appcelerator Titanium
Hard-coded left and top values break across screen sizes. Here is how Titanium's flex layout on Titanium.UI.View handles a responsive header, plus its limits.
18 May 2026, 02:48 UTC

The pixel-perfect trap
Mobile UI work often starts from a static mockup. The temptation is to translate those exact coordinates into code with left and top on every view. That works until the app runs on a device with a different aspect ratio, a different density bucket, or a longer localized string. Then the layout either overlaps or leaves dead space.
The alternative inside Appcelerator Titanium is to let a container decide how its children share space. Titanium's Titanium.UI.View supports a layout: 'flex' mode that behaves like a subset of CSS flexbox, so you describe relationships ("this label takes the leftover width") instead of coordinates.
Version assumption: flex layout in Titanium is a partial implementation of the CSS model and its supported properties have changed across SDK releases. Treat the property names below as a starting point and confirm them against the release notes for the SDK version you actually build with. If your project pins an older SDK, verify each property before depending on it.
What a flex container actually does
Setting layout: 'flex' on a parent view turns it into a flex container. Its direct children are laid out along a main axis and a cross axis, and three per-child properties control how space is divided:
- flexGrow — how much of the leftover space a child claims relative to its siblings.
- flexShrink — how much a child gives up when the children together exceed the container.
- flexBasis — the child's starting size before leftover space is distributed.
Two container properties handle alignment: justifyContent along the main axis and alignItems along the cross axis. Combined, they cover most centering and spacing cases that would otherwise need per-platform arithmetic.
Worked example: a header that survives long titles
A common requirement is a header with an icon on the left, a title in the middle, and an action icon on the right. The title length is unknown at build time, and the two icons should keep their size. Run the following in a Titanium controller file (for example app/controllers/main.js); it needs no special permissions beyond the normal UI ones.
// app/controllers/main.js
// Assumes a recent Titanium SDK with flex layout support.
// Verify property support for your SDK version before shipping.
const header = Ti.UI.createView({
layout: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: '#f5f5f5',
height: 60,
width: Ti.UI.FILL
});
const logo = Ti.UI.createImageView({
image: 'logo.png',
width: 40,
height: 40,
flexShrink: 0 // icons keep their size
});
const title = Ti.UI.createLabel({
text: 'My App',
flexGrow: 1, // claims the leftover middle space
flexShrink: 1,
textAlign: 'center'
});
const profile = Ti.UI.createImageView({
image: 'user.png',
width: 40,
height: 40,
flexShrink: 0
});
header.add(logo);
header.add(title);
header.add(profile);
Why this holds up: justifyContent: 'space-between' pins the icons to the edges, and flexGrow: 1 on the label means it absorbs whatever width is left. With flexShrink: 0 on the icons, a long title cannot squash them to nothing — the label shrinks instead. That is the behaviour you want, and it is expressed once rather than repeated per device class.
Trade-offs and failure modes
Flex is not free, and it is not a complete CSS engine.
- Layout-pass cost. Every resize or orientation change forces the engine to recompute child geometry. Deeply nested flex containers multiply that work, and the effect is most visible on low-end Android hardware during transitions. Flattening the view hierarchy is usually cheaper than tuning flex properties.
- Collapse without a baseline. A child with
flexGrowbut noflexBasis, width, or min/max constraint can end up with an unexpectedly small size when its content is empty or the container is unusually narrow. Give critical elements a floor. - Cross-platform drift. Older Titanium versions have been reported to differ between iOS and Android for some flex properties. If you must support an old SDK, budget time for platform-specific overrides rather than assuming identical results.
If your layout is a fixed grid of equal cells, absolute positioning or Titanium's classic layout: 'horizontal'/'vertical' modes may be simpler and cheaper. Flex earns its keep when sizes are genuinely content-dependent.
How to check the result
- Build to both an iOS simulator and an Android emulator and compare the same screen side by side. Differences in spacing or alignment at this stage are the ones that will bite in production.
- Rotate from portrait to landscape and confirm elements redistribute without overlap or gaps.
- Replace short labels with very long strings and confirm the shrink behaviour you intended actually happens.
- Test the smallest and largest screen sizes you support, and add
maxWidthorminWidthwhere a growing element stretches too far.
None of these checks prove correctness on every device; they catch the common regressions. For anything version-sensitive, confirm against the Titanium SDK documentation for your exact release before relying on it.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.