-
Notifications
You must be signed in to change notification settings - Fork 415
Advanced Theming
Codename One themes are pluggable CSS like elements that allow developers to determine/switch the look of the application in runtime. A theme can be installed via the UIManager class and themes can be layered one on top of the other (like CSS).
By default, Codename One themes derive the native operating system themes, although this behavior is entirely optional.
A theme initializes the Style objects, which are then used by the components to render themselves or by the LookAndFeel & DefaultLookAndFeel classes to create the appearance of the application.
Codename One themes have some built-in defaults, e.g. borders for buttons and padding/margin/opacity for various components. These are a set of “common sense” defaults that can be overridden within the theme.
UIID’s (User Interface IDentifier) are "effectively" a unique qualifier given to UI components that allows associating a set of theme definitions with a specific set of components. The class name of the component is commonly the same by default as the UIID, but they are in essence separate entities.
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);
UIID can be customized via the GUI builder and allows for powerful selection of individual components.
There are multiple defaults defined for elements within Codename One, e.g. a Container defaults to zero padding/margin and full transparency.
By default, every style inherits from these common cross platform defaults. Other than that, a theme may derive from the platform native theme providing further defaults.
In the designer, we can define whether a specific entry derives from the global default or defines its own override:
By unchecking the derive flag, we can override the appearance of a specific entry within the style.
The Derive entry within the style allows a specific style to derive and extend another style, e.g. a Button selected style can derive from a Button unselected style, thus removing the need to redefine style behavior for every state. This is very useful when defining commonalities among entries in a theme.
The colors of the style are represented as web style RGB entries, the foreground color is usually used to draw text. The background color applies when a border isn’t defined. Transparency is only used to draw the background color when applicable.
The background tab is one of the more elaborate entries within the style section. Notice that a background will only apply when no border is defined.
In general, 2 types of background are supported: Image or Gradient. You can pick several modes for each. For the gradients you can pick a horizontal, vertical or radial gradient.
In the case of gradients, you need to define all the gradient variables mentioned within the screen to define the source/destination colors, and in the case of a radial, the properties relevant to that.
When using an image background there are basically three options: Scaled, Tiled or Aligned.
An image can be scaled across the background of the component; this can create a decent effect in some cases but often causes some distortion. You can use scale to fit/fill, both of which create a more compelling scale effect that preserves aspect ratio.
An image can be aligned to a specific location within the component background, in which case the component will be painted based on the transparency setting, and the image will be painted in the appropriate location, based on the alignment. Finally, an image can be tiled either completely over the background or tiled as a single row/column aligned to a specific area within the component.
Codename One supports 2 major font types:[1] system fonts and truetype fonts (TTF). The system fonts are very limited in selection, but are highly recommended for portability. They use the built in font on the given device, which is often the font the user is used to. A developer has a selection from one of 3 generic sizes (small, medium, or large) and basic style choices (bold/plain/italic).
When a specific truetype font is needed, Codename One allows the developer to place a truetype font within the src directory of the project. This font will be automatically detected by the designer tool and offered as an option. Since truetype fonts are only supported on iOS, Android and Blackberry devices; you should still define a system font, which will be used as a fallback on unsupported platforms.
Notice that the file must have the ".ttf" extension, otherwise the build server won’t be able to recognize the file as a font and set it up accordingly (devices need fonts to be defined in very specific ways). Once you do that, you can use the font from code or from the theme.
Truetype fonts allow specifying their sizes using one of 3 approaches:
-
System font size scheme - the truetype font will have the same size as a small, medium or large system font. This allows the developer to size the font based on the device DPI.
-
Millimeter size - allows sizing the font in a more DPI aware size.
-
Pixels - useful for some unique cases, but highly problematic in multi-DPI scenarios.
To use fonts from code, just use:
if(Font.isTrueTypeFileSupported()) {
Font myFont = Font.createTrueTypeFont(fontName, fontFileName);
myFont = myFont.derive(sizeInPixels, Font.STYLE_PLAIN);
// do something with the font
}
Notice that, in code, only pixel sizes are supported, so it’s up to you to decide how to convert that. You also need to derive the font with the proper size, unless you want a 0 sized font which probably isn’t very useful.
The font name is the difficult bit, iOS requires the name of the font, which doesn’t always correlate to the file name, in order to load the font, it’s sometimes viewable within a font viewer. It isn’t always intuitive, so be sure to test that on the device to make sure you got it right.
See the theme basics above about cutting a 9-piece border using the image border class. Codename One supports configuring the border according to several configurations:
When pressing the ‘…’ button you can customize the border using multiple configuration types:
There are several border types that can be used to customize the look of the component.
Padding and margin are concepts derived from the CSS box model. Its slightly different in Codename One, where the border spacing is part of the padding, but other than that they are pretty similar:
In the above diagram, we can see the component represented in yellow occupying its preferred size. The padding portion in gray effectively increases the components size. The margin is an area, which effectively belongs to the component, but the component doesn’t draw anything within that area, it is represented in red.
The theme allows us to customize the padding/margin, and specify them for all 4 sides of a component. They can be specified in pixels, millimeters, or screen percentage:
Padding is especially important when a border is defined and we need to space the component drawing from the edge of the border. Margin allows us to space components from one another easily and create “whitespace” within the user interface.
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, they have some conventions where a constant ending with Bool is treated as a boolean (true/false) value and a constant ending with Int or Image (for image the string name of the image is stored, but the image instance will be returned).
NOTICE: 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 will try to keep this list up to date.
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 |
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 |
One "odd" behavior of constants is that, once they are set by a theme, they don’t get "lost" 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.
Codename One themes are effectively a simple hashtable containing key/value pairs. Such a hashtable is passed on to the setThemeProps()
method of the UIManager (or one of its equivalents e.g. addThemeProps()
) to install a theme.
When a Codename One component is rendered or laid out, style related data is requested, in which case the UIManager generates a Style object based on the theme hashtable values.
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();
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 straightforward, and it 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).
The reason for this is DPI or device density, the density of the devices varies significantly and Codename One tries to make matters simple by unifying everything into one set of values to indicate density. For simplicity’s sake, density is expressed in terms of pixels, but 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 much better on all the different resolutions. Since scaling on the device can’t interpolate the data (due to performance considerations), 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 completely 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 rely on understanding the source resolution of the image, e.g. 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 very high density and it will scale for the rest of the densities accordingly.
Alternatively, you can use the standard add multi-image dialog and set it like this:
Notice that I selected square images, 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:
Constant |
Density |
Example Device |
|
~ 88 ppi |
|
|
~ 120 ppi |
Android ldpi devices |
|
~ 160 ppi |
iPhone 3GS, iPad, Android mdpi devices |
|
~ 240 ppi |
Android hdpi devices |
|
~ 320 ppi |
iPhone 4, iPad Air 2, Android xhdpi devices |
|
~ 540 ppi |
iPhone 6+, Android xxhdpi devices |
|
~ 750 ppi |
Android xxxhdpi devices |
|
~ 1000 ppi |
|
|
~ 1250ppi |
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 millimetres for all non-zero units of measurement.
Sometimes millimetres 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 millimetres (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);
If you’re using system fonts (the default), then you’re limited to only three font sizes: Small, Medium, and Large.
These will be converted to an appropriate "real" size on the device. If you need more precision, you can embed a
TTF font with your app, then you can specify font size in millimetres (or DIPS). And if you require more precision
on the font size than millimetres, you can use the same trick above to obtain a fractional millimetres to pixels
conversion, and use the Font.deriveFont()
method to generate a font in the exact "real" size that you desire.
About This Guide
Introduction
Basics: Themes, Styles, Components & Layouts
Theme Basics
Advanced Theming
Working With The GUI Builder
The Components Of Codename One
Using ComponentSelector
Animations & Transitions
The EDT - Event Dispatch Thread
Monetization
Graphics, Drawing, Images & Fonts
Events
File-System,-Storage,-Network-&-Parsing
Miscellaneous Features
Performance, Size & Debugging
Advanced Topics/Under The Hood
Signing, Certificates & Provisioning
Appendix: Working With iOS
Appendix: Working with Mac OS X
Appendix: Working With Javascript
Appendix: Working With UWP
Security
cn1libs
Appendix: Casual Game Programming