Skip to content
Shai Almog edited this page Feb 9, 2016 · 35 revisions

Working With UIID’s

UIID’s (User Interface IDentifier) are unique qualifiers given to UI components that associate a set of theme definitions with a specific set of components. E.g. we can associate the Button UIID with a component and then define the look for the Button in the theme.

One of the biggest advantages with UIID’s is the ability to change the UIID of a component. E.g. to create a multiline label, one can use something like:

TextArea t = …;
t.setUIID("Label");
t.setEditable(false);
Tip
This is pretty much how components such as SpanLabel are implemented internally.

UIID’s can be customized via the GUI builder and allows for powerful customization of individual components.

Note
The class name of the component is commonly the same as the UIID, but they are in essence separate entities.

Theme Layering

There are two use cases in which you would want to use layering:

  • You want a slightly different theme in one platform

  • You want the ability to customize your theme for a specific use case, e.g. let a user select larger fonts

This is actually pretty easy to do and doesn’t require re-doing the entire theme. You can do something very similar to the cascading effect of CSS where a theme is applied "on top" of another theme. To do that just add a new theme using the Add Theme button.

Important
Make sure to remove the includeNativeBool constant in the new theme!

In the new theme define the changes e.g. if you just want a larger default font define only that property for all the relevant UIID’s and ignore all other properties!

For a non-gui builder app the theme loading looks like this by default:

theme = UIManager.initFirstTheme("/theme");

You should fix it to look like this:

theme = UIManager.initNamedTheme("/theme", "Theme");
Note
This assumes the name of your main theme is "Theme" (not the layer theme you just added).

The original code relies on the theme being in the 0 position in the theme name array which might not be the case!

When you want to add the theme layer just use:

UIManager.getInstance().addThemeProps(theme.getTheme("NameOfLayerTheme"));

The addThemeProps call will layer the secondary theme on top of the primary "Theme" and keep the original UIID’s defined in the "Theme" intact.

If you apply theme changes to a running application you can use Form’s `refreshTheme() to update the UI instantly and provide visual feedback for the theme changes.

Override Resources In Platform

When we want to adapt the look of an application to different OS conventions one of the common requirements is to use different icons. Sometimes we want to change behavior based on device type e.g. have a different UI structure for a Tablet.

Codename One allows you to override a resource for a specific platform when doing this you can redefine a resource differently for that specific platform and also add platform specific resources.

Override resources for specific platform
Figure 1. Override resources for specific platform

Overriden resources take precedence over embedded resources thus allowing us to change the look or even behavior (when overriding a GUI builder element) for a specific platform/OS.

Important
Overriding the theme is dangerous as a theme has external dependencies (e.g. image borders). The solution is to use theme layering and override the layer!

To override select the platform where overriding is applicable

Override for platform
Figure 2. Override for platform, allows us to override the checked resources and replace them with another resource

You can then click the green checkbox to define that this resource is specific to this platform. All resources added when the platform is selected will only apply to the selected platform. If you change your mind and are no longer interested in a particular override just delete it in the override mode and it will no longer be overridden.

Theme Constants

The Codename One Designer has a tab for creating constants which can be used to add global values of various types and behavior hints to Codename One and its components. Constants are always strings, there are some conventions that allow the UI to adapt to input various types more easily e.g. if a constant ends with the word Bool it is treated as a boolean (true/false) value and will be displayed as a checkbox. Similarly Int will display a numeric picker and Image will show a combo box to pick an image.

Important
The combo box in the designer for adding a theme constant is editable, you can just type in any value you want!

To use a constant one can use the UIManager's methods to get the appropriate constant type specifically:

  • getThemeConstant

  • isThemeConstant

  • getThemeImageConstant

Internally, Codename One has several built in constants and the list is constantly growing. As we add features to Codename One, we try to keep this list up to date but the very nature of theme constants is "adhoc" and some might not make it here.

Table 1. Theme Constants
Constant Description/Argument

alwaysTensileBool

Enables tensile drag even when there is no scrolling in the container (only for scrollable containers)

backGestureThresholdInt

The threshold for the back gesture in the SwipeBackSupport class, defaults to 5

backUsesTitleBool

Indicates to the GUI builder that the back command should use the title of the previous form and not just the word "Back"

defaultCommandImage

Image to give a command with no icon

dialogButtonCommandsBool

Place commands in the dialogs as buttons

dialogPosition

Place the dialog in an arbitrary border layout position (e.g. North, South, Center, etc.)

centeredPopupBool

Popup of the combo box will appear in the center of the screen

changeTabOnFocusBool

Useful for feature phones, allows changing the tab when the focus changes immediately, without pressing a key

checkBoxCheckDisImage

CheckBox image to use instead of Codename One drawing it on its own

checkBoxCheckedImage

CheckBox image to use instead of Codename One drawing it on its own

checkBoxOppositeSideBool

Indicates the check box should be drawn on the opposite side to the text and not next to the text

checkBoxUncheckDisImage

CheckBox image to use instead of Codename One drawing it on its own

checkBoxUncheckedImage

CheckBox image to use instead of Codename One drawing it on its own

comboImage

Combo image to use instead of Codename One drawing it on its own

commandBehavior

Indicates how commands should act, as a touch menu, native menu etc. Possible values: SoftKey, Touch, Bar, Title, Right, Native

ComponentGroupBool

Enables component group, which allows components to be logically grouped together, so the UIID’s of components would be modified based on their group placement. This allows for some unique styling effects where the first/last elements have different styles from the rest of the elements. It’s disabled by default, thus leaving its usage up to the designer

dialogTransitionIn

Default transition for dialog

dialogTransitionInImage

Default transition Image for dialog, causes a Timeline transition effect

dialogTransitionOut

Default transition for dialog

defaultCommandImage

An image to place on a command if none is defined, only applies to touch commands

defaultEmblemImage

The emblem painted on the side of the multibutton, by default this is an arrow on some platforms

dialogTransitionOutImage

Default transition Image for dialog, causes a Timeline transition effect

disabledColor

Color to use when disabling entries by default

dlgButtonCommandUIID

The UIID used for dialog button commands

dlgCommandButtonSizeInt

Minimum size to give to command buttons in the dialog

dlgCommandGridBool

Places the dialog commands in a grid for uniform sizes

dlgInvisibleButtons

Includes an RRGGBB color for the line separating dialog buttons, as is the case with Android 4 and iOS 7 buttons in dialogs

dlgSlideDirection

Slide hints

dlgSlideInDirBool

Slide hints

dlgSlideOutDirBool

Slide hints

drawMapPointerBool

Indicates whether a pointer should appear in the center of the map component

fadeScrollBarBool

Boolean indicating if the scrollbar should fade when there is inactivity

fadeScrollEdgeBool

Places a fade effect at the edges of the screen to indicate that it’s possible to scroll until we reach the edge (common on Android)

fadeScrollEdgeInt

Amount of pixels to fade out at the edge

firstCharRTLBool

Indicates to the GenericListCellRenderer that it should determine RTL status based on the first character in the sentence

noTextModeBool

Indicates that the on/off switch in iOS shouldn’t draw text on top of the switch, which is the case for iOS 7+ but not for prior versions

fixedSelectionInt

Number corresponding to the fixed selection constants in List

formTransitionIn

Default transition for form

formTransitionInImage

Default transition Image for form, causes a Timeline transition effect

formTransitionOut

Default transition for form

formTransitionOutImage

Default transition Image for form, causes a Timeline transition effect

hideBackCommandBool

Hides the back command from the side menu when possible

hideEmptyTitleBool

Indicates that a title with no content should be hidden even if the border for the title occupies space

hideLeftSideMenuBool

Hides the side menu icon that appears on the left side of the UI

ignorListFocusBool

Hide the focus component of the list when the list doesn’t have focus

infiniteImage

The image used by the infinite progress component, the component will rotate it as needed

includeNativeBool

True to derive from the platform native theme, false to create a blank theme that only uses the basic defaults

listItemGapInt

Built-in item gap in the list, this defaults to 2, which predated padding/margin in Codename One

listLongPressBool

Indicates whether a list should handle long press events, defaults to true

mapTileLoadingImage

An image to preview while loading the MapComponent tile

mapTileLoadingText

The text of the tiles in the MapComponent during loading, defaults to "Loading…​"

mapZoomButtonsBool

Indicates whether buttons should be drawn on the map component

mediaBackImage

Media icon used by the media player class

mediaFwdImage

Media icon used by the media player class

mediaPauseImage

Media icon used by the media player class

mediaPlayImage

Media icon used by the media player class

menuButtonBottomBool

When set to true this flag aligns the menu button to the bottom portion of the title. Defaults to false

menuButtonTopBool

When set to true this flag aligns the menu button to the top portion of the title. Defaults to false

menuHeightPercent

Allows positioning and sizing the menu

menuImage

The three dot menu image used in Android and the Toolbar to show additional command entries

menuPrefSizeBool

Allows positioning and sizing the menu

menuSlideDirection

Defines menu entrance effect

menuSlideInDirBool

Defines menu entrance effect

menuSlideOutDirBool

Defines menu entrance effect

menuTransitionIn

Defines menu entrance effect

menuTransitionInImage

Defines menu entrance effect

menuTransitionOut

Defines menu exit effect

menuTransitionOutImage

Defines menu entrance effect

menuWidthPercent

Allows positioning and sizing the menu

minimizeOnBackBool

Indicates whether the form should minimize the entire application when the physical back button is pressed (if available) and no command is defined as the back command. Defaults to true

onOffIOSModeBool

Indicates whether the on/off switch should use the iOS or Android mode

otherPopupRendererBool

Indicates that a separate renderer UIID/instance should be used to the list within the combo box popup

PackTouchMenuBool

Enables preferred sized packing of the touch menu (true by default), when set to false this allows manually determining the touch menu size using percentages

paintsTitleBarBool

Indicates that the StatusBar UIID should be added to the top of the form to space down the title area, as is the case on iOS 7+ where the status bar is painted on top of the UI

popupCancelBodyBool

Indicates that a cancel button should appear within the combo box popup

PopupDialogArrowBool

Indicates whether the popup dialog has an arrow, notice that this constant will change if you change UIID of the popup dialog

PopupDialogArrowBottomImage

Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog

PopupDialogArrowTopImage

Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog

PopupDialogArrowLeftImage

Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog

PopupDialogArrowRightImage

Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog

popupNoTitleAddPaddingInt

Adds padding to a popup when no title is present

popupTitleBool

Indicates that a title should appear within the combo box popup

pullToRefreshImage

The arrow image used to draw the pullToRefresh animation

pureTouchBool

Indicates the pure touch mode

radioOppositeSideBool

Indicates the radio button should be drawn on the opposite side to the text and not next to the text

radioSelectedDisImage

Radio button image

radioSelectedImage

Radio button image

radioUnselectedDisImage

Radio button image

radioUnselectedImage

Radio button image

releaseRadiusInt

Indicates the distance from the button with dragging, in which the button should be released, defaults to 0

rendererShowsNumbersBool

Indicates whether renderers should render the entry number

reverseSoftButtonsBool

Swaps the softbutton positions

rightSideMenuImage

Same as sideMenuImage only for the right side, optional and defaults to sideMenuImage

rightSideMenuPressImage

Same as sideMenuPressImage only for the right side, optional and defaults to sideMenuPressImage

showBackCommandOnTitleBool

Used by the Toolbar API to indicate whether the back button should appear on the title

shrinkPopupTitleBool

Indicates the title of the popup should be set to 0 if it’s missing

sideMenuAnimSpeedInt

The speed at which a sidemenu moves defaults to 300 milliseconds

sideMenuFoldedSwipeBool

Indicates the side menu could be opened via swiping

sideMenuImage

The image representing the side menu, three lines (Hamburger menu)

sideMenuPressImage

Optional pressed version of the sideMenuImage

sideMenuShadowBool

Indicates whether the shadow for the side menu should be drawn

sideMenuShadowImage

The image used when drawing the shadow (a default is used if this isn’t supplied)

sideMenuSizeTabPortraitInt

The size of the side menu when expanded in a tablet in portrait mode

sideMenuSizePortraitInt

The size of the side menu when expanded in a phone in portrait mode

sideMenuSizeTabLandscapeInt

The size of the side menu when expanded in a tablet in landscape mode

sideMenuSizeLandscapeInt

The size of the side menu when expanded in a phone in landscape mode

sideMenuTensileDragBool

Enables/disables the tensile drag behavior within the opened side menu

sideSwipeActivationInt

Indicates the threshold in the side menu bar at which a swipe should trigger activation, defaults to 15 (percent)

sideSwipeSensitiveInt

Indicates the region of the screen that is sensitive to side swipe in the side menu bar, defaults to 10 (percent)

slideDirection

Default slide transition settings

slideInDirBool

Default slide transition settings

slideOutDirBool

Default slide transition settings

sliderThumbImage

The thumb image that can appear on the sliders

snapGridBool

Snap to grid toggle

statusBarScrollsUpBool

Indicates that a tap on the status bar should scroll up the UI, only relevant in OS’s where paintsTitleBarBool is true

switchButtonPadInt

Indicates the padding in the on/off switch, defaults to 16

switchMaskImage

Indicates the mask image used in iOS mode to draw on top of the switch

switchOnImage

Indicates the on image used in iOS mode to draw the on/off switch

switchOffImage

Indicates the off image used in iOS mode to draw the on/off switch

TabEnableAutoImageBool

Indicates images should be filled by default for tabs

TabSelectedImage

Default selected image for tabs (if TabEnableAutoImageBool=true)

TabUnselectedImage

Default unselected image for tabs (if TabEnableAutoImageBool=true)

tabPlacementInt

The placement of the tabs in the Tabs component: TOP = 0, LEFT = 1, BOTTOM = 2, RIGHT = 3

tabsFillRowsBool

Indicates if the tabs should fill the row using flow layout

tabsGridBool

Indicates whether tabs should use a grid layout thus forcing all tabs to have identical sizes

tabsOnTopBool

Indicates the tabs should be drawn on top of their content in a layered UI, this allows a tab to intrude into the content of the tabs

textCmpVAlignInt

The vertical alignment of the text component: TOP = 0, CENTER = 4, BOTTOM = 2

textFieldCursorColorInt

The color of the cursor as an integer (not hex)

tickerSpeedInt

The speed of label/button etc. (in milliseconds)

tintColor

The aarrggbb hex color to tint the screen when a dialog is shown

topMenuSizeTabPortraitInt

The size of the side menu when expanded and attached to the top in a tablet in portrait mode

topMenuSizePortraitInt

The size of the side menu when expanded and attached to the top in a phone in portrait mode

topMenuSizeTabLandscapeInt

The size of the side menu when expanded and attached to the top in a tablet in landscape mode

topMenuSizeLandscapeInt

The size of the side menu when expanded and attached to the top in a phone in landscape mode

touchCommandFillBool

Indicates how the touch menu should layout the commands within

touchCommandFlowBool

Indicates how the touch menu should layout the commands within

transitionSpeedInt

Indicates the default speed for transitions

treeFolderImage

Picture of a folder for the Tree class

treeFolderOpenImage

Picture of a folder expanded for the Tree class

treeNodeImage

Picture of a file node for the Tree class

tensileDragBool

Indicates that tensile drag should be enabled/disabled. This is usually set by platform themes

Dynamic Theme Swapping & Theme Constants

Once a theme constant is set by a theme, it isn’t removed on a refresh when replacing the theme.

E.g. if one would set the comboImage constant to a specific value in theme A and then switch to theme B, that doesn’t define the comboImage, the original theme A comboImage might remain!

The reason for this is simple: when extracting the constant values, components keep the values in cache locally and just don’t track the change in value. Furthermore, since the components allow manually setting values, it’s impractical for them to track whether a value was set by a constant or explicitly by the user.

The solution for this is to either manually reset undesired values before replacing a theme (e.g. for the case, above by calling the default look and feel method for setting the combo image with a null value), or defining a constant value to replace the existing value.

Native Theming

Codename One uses a theme constant called includeNativeBool, when that constant is set to true Codename One starts by loading the native theme first and then applying all the theme settings. This effectively means your theme "derives" the style of the native theme first, similar to the cascading effect of CSS. Internally this is exactly what the theme layering section covered.

By avoiding this flag you can create themes that look EXACTLY the same on all platforms.

Warning
If you avoid the native theming you you might be on your own. A few small device oddities such as the iOS status bar are abstracted by native theming. Without it you will need to do everything from scratch.

You can simulate different OS platforms by using the native theme menu option

The native theme menu option
Figure 3. The native theme menu option

Developers can pick the platform of their liking and see how the theme will appear in that particular platform by selecting it and having the preview update on the fly.

How Does A theme Work?

To truly understand a theme we need to understand what it is. Internally a theme is just a Hashtable key/value pair between UIID based keys and their respective values. E.g. the key:

Button.fgColor=ffffff

Will set the foreground color of the Button UIID to white.

When a Codename One Component is instantiated it requests a Style object from the UIManager class. The Style object is based on the settings within the theme and can be modified thru code or by using the theme.

We can replace the theme dynamically in runtime and refresh the styles assigned to the various components using the refreshTheme() method.

Note
It’s a common mistake to invoke refreshTheme() without actually changing the theme. We see developers doing it when all they need is a repaint() or revalidate(). Since refreshTheme() is very expensive we recommend that you don’t use it unless you really need to…​

A theme Hashtable key is comprised of:

[UIID.][type#]attribute

The UIID, corresponds to the component’s UIID e.g. Button, CheckBox etc. It is optional and may be omitted to address the global default style.

The type is omitted for the default unselected type, and may be one of sel (selected type), dis (disabled type) or press (pressed type). The attribute should be one of:

  • derive - the value for this attribute should be a string representing the base component.

  • bgColor - represents the background color for the component, if applicable, in a web hex string format RRGGBB e.g. ff0000 for red.

  • fgColor - represents the foreground color, if applicable.

  • border - an instance of the border class, used to display the border for the component.

  • bgImage - an Image object used in the background of a component.

  • transparency - a String containing a number between 0-255 representing the alpha value for the background. This only applies to the bgColor.

  • margin - the margin of the component as a String containing 4 comma separated numbers for top,bottom,left,right.

  • padding - the padding of the component, it has an identical format to the margin attribute.

  • font - A Font object instance.

  • alignment - an Integer object containing the LEFT/RIGHT/CENTER constant values defined in Component.

  • textDecoration - an Integer value containing one of the TEXT_DECORATION_* constant values defined in Style.

  • backgroundType - a Byte object containing one of the constants for the background type defined in Style under BACKGROUND_*.

  • backgroundGradient - contains an Object array containing 2 integers for the colors of the gradient. If the gradient is radial it contains 3 floating points defining the x, y & size of the gradient.

So to set the foreground color of a selected button to red, a theme will define a property like:

Button.sel#fgColor=ff0000

This information is mostly useful for understanding how things work within Codename One, but it can also be useful in runtime.

E.g. to increase the size of all fonts in the application, we can do something like:

Hashtable h = new Hashtable();
h.put("font", largeFont);
UIManager.getInstance().addThemeProps(h);
Display.getInstance().getCurrent().refreshTheme();

Understanding Images & Multi-Images

Note
This section provides a very high level overview of images. We dive deeper into the various types of images in the graphics section.

When working with a theme, we often use images for borders or backgrounds. We also use images within the GUI for various purposes and most such images will be extracted from the resource file.

Adding a standard JPEG/PNG image to the resource file is straight forward, and the resulting image can be viewed within the images section. However, due to the wide difference between device types, an image that would be appropriate in size for an iPhone 3gs would not be appropriate in size for a Nexus device or an iPhone 4 (but perhaps, surprisingly, it will be just right for iPad 1 & iPad 2).

Device Density: DPI/PPI

DPI (Dots Per Inch) & PPI (Pixels Per Inch) are two shorthand terms used to discuss the variety of device densities. Densities are confusing for first time Codename One developers who struggle with the notion that an iPad might get the same resolution image as a phone.

A first generation the iPad 2 device had a 160 PPI (160 pixels per inch density). The much smaller iPhone 4 from the same era had 320 PPI and modern devices already exceed 600+ PPI values. The contrast is staggering especially when compared to the desktop.

Mobile UI’s are expected to use all available pixels to their full extent. In that sense when an application runs on a tablet you don’t want it to just provide a larger image for the icons but rather have it cram more information into a single form. So we need to rethink image sizing not just in pixels but in millimeters/inches.

The density of the devices varies significantly and Codename One tries to simplify the process by unifying everything into one set of values to indicate density. For simplicity’s sake, density is sometimes expressed in terms of pixels, however it is mapped internally to actual screen measurements where possible.

A multi-image is an image that has multiple varieties for different densities, and thus looks sharp in all the densities. Since scaling on the device can’t interpolate the data (due to performance considerations), significant scaling on the device becomes impractical. However, a multi-image will just provide the “right” resolution image for the given device type.

From the programming perspective this is mostly seamless, a developer just accesses one image and has no ability to access the images in the different resolutions. Within the designer, however, we can explicitly define images for multiple resolutions and perform high quality scaling so the “right” image is available.

We can use two basic methods to add a multi-image: quick add & standard add.

Both methods rely on understanding the source resolution of the image, e.g. if you have an icon that you expect to be 128x128 pixels on iPhone 4, 102x102 on nexus one and 64x64 on iPhone 3gs. You can provide the source image as the 128 pixel image and just perform a quick add option while picking the Very High density option.

This will indicate to the algorithm that your source image is designed for the "very high" density and it will scale for the rest of the densities accordingly.

Tip
This relies on the common use case of asking your designer to design for one high end device (e.g. iPhone 6+) then you can just take the resources and add them as "HD" resources and they will automatically adapt to the lower resolutions.

Alternatively, you can use the standard add multi-image dialog and set it like this:

Multi-image resolution dialog

Notice that we selected the square image option, essentially eliminating the height option. Setting values to 0 prevents the system from generating a multi-image entry for that resolution, which will mean a device in that category will fall on the closest alternative.

The percentage value will change the entire column, and it means the percentage of the screen. E.g. We know the icon is 128 for the very high resolution, we can just move the percentage until we reach something close to 128 in the “Very High” row and the other rows will represent a size that should be pretty close in terms of physical size to the 128 figure.

At runtime, you can always find the host device’s approximate pixel density using the Display.getDeviceDensity() method. This will return one of:

Table 2. Densities

Constant

Density

Example Device

Display.DENSITY_VERY_LOW

~ 88 ppi

Display.DENSITY_LOW

~ 120 ppi

Android ldpi devices

Display.DENSITY_MEDIUM

~ 160 ppi

iPhone 3GS, iPad, Android mdpi devices

Display.DENSITY_HIGH

~ 240 ppi

Android hdpi devices

Display.DENSITY_VERY_HIGH

~ 320 ppi

iPhone 4, iPad Air 2, Android xhdpi devices

Display.DENSITY_HD

~ 540 ppi

iPhone 6+, Android xxhdpi devices

Display.DENSITY_560

~ 750 ppi

Android xxxhdpi devices

Density.DENSITY_2HD

~ 1000 ppi

Density.DENSITY_4K

~ 1250ppi

Use Millimeters for Padding/Margin & Font Sizes

When configuring your styles, you should almost never use "Pixels" as the unit for padding, margins, font size, and border thickness because the results will be inconsistent on different densities. Instead, you should use millimeters for all non-zero units of measurement.

As we now understand the complexities of DPI it should be clear why this is important.

Fractions of Millimeters

Sometimes millimeters don’t give you enough precision for what you want to do. Currently the designer only allows you to specify integer values for most units. However, you can achieve more precise results when working directly in Java. The Display.convertToPixels() method will allow you to convert millimeters (or DIPS) to pixels. It also only takes an integer input, but you can use it to obtain a multiplier that you can then use to convert any millimeter value you want into pixels.

E.g.

double pixelsPerMM = ((double)Display.getInstance().convertToPixels(10, true)) / 10.0;

And now you can set the padding on an element to 1.5mm. E.g.

myButton.getAllStyles().setPaddingUnit(Style.UNIT_TYPE_PIXELS);
int pixels = (int)(1.5 * pixelsPerMM);
myButton.getAllStyles().setPadding(pixels, pixels, pixels, pixels);
Clone this wiki locally