Mobile control API
nexus.ui is a Lua library built into the Nexus mobile engine. The Windows,
Linux, Android and Apple engine build descriptions include its modules. The
supplied artwork is packaged with the engine's system resources. Applications
use the same import in the simulator and on the device:
local ui = require("nexus.ui")
local panel = ui.newPanel {parent = scene.view, width = 320, height = 480}
local name = ui.newEdit {parent = panel, y = -40, placeholder = "Your name"}
local save = ui.newButton {
parent = panel, y = 40, text = "Save",
onClick = function() saveCustomer(name.text) end
}
save.text = "Save changes"
save.enabled = false
Controls are engine display groups. parent, x and y place them in an
existing scene; coordinates are relative to the parent. Control rectangles
are centered on their local origin. Use the engine's normal transforms,
visibility, ordering and removal operations. width and height change the
control's arrangement and artwork without scaling its text. xScale and
yScale retain their normal engine meaning.
parent = anotherControl inserts into that control's public content group.
Use control.content:insert(object) for ordinary display objects. Removing a
scene or containing group disposes the controls through engine finalization;
applications do not maintain a second ownership tree. Disable a containing
control to prevent interaction with its descendants.
Controls
All constructors accept parent, x, y, width, height, id, enabled
and an optional control-specific skin table. Text uses Lua UTF-8 strings.
| Constructor | Additional options/properties | Events/methods |
|---|---|---|
newPanel |
— | content for children |
newLabel |
text, align |
— |
newButton |
text |
onClick |
newCheckbox |
text, checked |
onChange, event.checked |
newToggle |
text, checked |
onChange, event.checked |
newRadioGroup |
items, selectedIndex, constructor rowHeight |
onChange, getItem() |
newEdit |
text, placeholder, readOnly, secure; constructor multiline, inputType, returnKey |
focus(), blur(), onFocus, onBlur, onChange, onSubmit |
newScrollView |
contentHeight, scrollY |
scrollTo(y), reveal(child, margin), onScroll |
newList |
items, selectedIndex, constructor rowHeight |
getItem(), refresh(), onChange, onClick; scroll methods |
newSlider |
value; constructor minimum, maximum, step |
onChange, event.value |
newProgress |
value; constructor minimum, maximum |
— |
Items are strings or application tables containing text. Selection events
provide selectedIndex and the original item; zero means no selection.
Replace a list's items property to rebuild its rows, or call refresh()
after modifying its existing item tables. Radio items are specified at
construction. Lists are ordinary scrollable rows, intended for mobile-sized
collections; this implementation does not virtualize very large datasets.
Callbacks receive event.target, the control itself. The same events are
available through the engine's control:addEventListener("change", listener)
mechanism. Use either form, or intentionally register both. Programmatic
property assignments update the display without reporting a user change.
Buttons activate on release inside their bounds. Cancelled or outside releases
do not activate them. A vertical drag on a control inside a scroll view transfers
the gesture to that viewport. Sliders retain horizontal drags. Scrolling uses
the engine's container clipping, touch focus and transitions for deceleration.
onScroll reports touch-drag movement; programmatic positioning and subsequent
deceleration do not generate additional callbacks.
Scroll content has its origin at the viewport's upper-left corner. Specify its
contentHeight after placing children. Panels retain ordinary centered local
coordinates and do not clip children automatically.
Text editing
An unfocused edit is drawn by the engine, including its frame and text. While focused it uses a borderless native text field or multiline text box inside the skinned frame. This preserves the phone's keyboard, text composition, selection and clipboard behavior. No additional native input bridge is used.
onChange supplies text and oldText; onSubmit reports a submitted
single-line edit. Multiline return inserts a newline. Use a Done/Save button
or ui.blur() to finish multiline editing. Text values are kept in Lua and
updated from the native input events, avoiding immediate Android readback
after asynchronous native writes.
Native editors render above the canvas. Scrolling their container ends editing;
another control's interaction also ends it. Call ui.blur() before presenting
custom overlays that cover an active edit. The enclosing scroll view reveals
an edit before focusing it. Native engine keyboard accommodation remains in
effect. The examples enable CoronaWindowMovesWhenKeyboardAppears in their
Android settings and iPhone plist, so the engine can move the window to keep
the focused editor above the keyboard. Mobile appearance and keyboard behavior must be checked on a device;
desktop execution is not evidence of mobile validation.
Desktop native editing follows the engine's platform implementation. Windows
does not support hasBackground, so an active editor retains its native
background. The Linux native text implementation has incomplete text-property,
styling and edit-notification support; its active editor is not yet equivalent
to the phone implementations.
Skins
Choose the default neutral appearance or the supplied nine-slice artwork:
ui.setSkin({})
ui.setSkin(require("nexus.ui.skins.artwork"))
setSkin affects subsequently constructed controls. Each control captures its
resolved skin. Assign control.skin = {...} to restyle an existing control.
Skin tables contain common settings and entries named panel, label,
button, checkbox, radio, toggle, edit, scroll, list, slider and
progress. Per-control overrides use just that control's style table.
Settings include font, fontSize, textColor, mutedColor, accentColor,
padding, gap, opacity and background. State tables selected, focused,
pressed and disabled override the base appearance in that order.
Nested fields merge; background = false removes a background.
Shape backgrounds accept color, radius, borderColor and borderWidth.
Nine-slice backgrounds accept an image and source-pixel borders:
local buttonSkin = {
textColor = {1, 1, 1},
background = {
type = "nineSlice", image = "art/button.png",
borders = {left = 12, top = 12, right = 12, bottom = 12}
},
pressed = {background = {image = "art/button-down.png"}},
disabled = {opacity = .45}
}
Alternatively provide sheet and nine frames indexes ordered left-to-right,
top-to-bottom. baseDir defaults to system.ResourceDirectory; tint colors
the slices. Borders remain fixed while the center and edges stretch. Controls
smaller than their border pairs shrink the borders together. A skin describes
appearance; input and state transitions remain in the control.
The supplied nexus_ui_frame.svg is the editable source of the original
nexus_ui_frame.png artwork. Custom image assets travel with the application's
normal resource files. Nine-slice drawing does not impose a mask on children.
Initial arrangement
ui.split(rect, ratio, gap, vertical) returns two center-based rectangles.
The ratio divides the usable extent after subtracting the gap. It performs
one calculation; call it again when the application wants another arrangement.
local left, right = ui.split({parent = scene.view, x = 200, y = 400,
width = 368, height = 600}, .35, 8)
local navigation = ui.newPanel(left)
local details = ui.newPanel(right)
Working examples are in nexus-lab/examples/mobile/controls: a control gallery
with both skins and a customer form with local persistence.