This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.
Light/dark mode
CrossFly switches between light and dark in real time and in place — without recreating screens. The key is
Styles.setDarkMode(...) combined with styles that re-resolve from the theme.
Complete example (copy, paste and run)
package com.exemplo;
import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*; // Styles, ThemeMode, LabelRole
/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
@Override
public void onShow() throws Exception
{
super.onShow();
Styles.setColorScheme(0xFF6750A4, ThemeMode.LIGHT); // base palette (follows light/dark)
setLayout(new VerticalLayout());
// styled(...) re-evaluates the style on each theme switch (automatic re-skin per mode)
Label titulo = new Label("Bem-vindo")
.styled(() -> Styles.theme().label(LabelRole.TITLE));
add(LAY_AUTO, titulo);
// Switch toggles the mode; setDarkMode re-skins the whole open UI on its own.
Switch alternar = new Switch("Modo escuro");
alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked()));
add(LAY_AUTO, alternar);
}
}
The snippets below show only the core (what goes inside
onShow()). To run them, place them in theMainWindowskeleton above.
The automatic way (recommended)
- Use theme
PalColor(Styles.textColor,cs.surface) in styles — they re-resolve themselves. - Call
setDarkMode(...):
Styles.toggleDarkMode(); // toggles light ↔ dark
Styles.setDarkMode(true); // forces dark
boolean escuro = Styles.isDarkMode(); // current state
setDarkMode(...) already re-applies the theme to all open windows automatically (it triggers
restyleAll() internally), so styles bound to PalColor change color without any extra code.
Styles that depend on the mode → styled(...) / onRestyle(...)
When the style changes shape according to the mode (not just the color), register how the component should re-style itself. The callback runs once immediately and again on each theme switch:
Label titulo = new Label("Bem-vindo")
.styled(() -> Styles.theme().label(LabelRole.TITLE)); // re-evaluated on each theme switch
// for logic beyond style (swap icon glyph, chart color, etc.):
Label l = new Label("Status");
l.onRestyle(() -> l.style(Styles.isDarkMode() ? estiloEscuro : estiloClaro));
Manual re-skin of a subtree
If you changed the theme non-globally (e.g., just one panel), force the reapplication:
window.restyle(); // re-runs all onRestyle in the tree and repaints, without recreating components
Complete flow
Switch alternar = new Switch("Modo escuro");
alternar.onAction(c -> Styles.setDarkMode(alternar.isChecked())); // the whole UI follows along
Best practices
- Prefer theme
PalColorover fixed colors — dark mode becomes automatic. - For styles that change structure per mode, use
styled(...)(leaner thanonRestyle). - Read the mode with
Styles.isDarkMode()/Styles.themeMode()when building styles.
Common mistakes
- Storing fixed colors (
0xFF...) and then having to rebuild the screen by hand for dark mode. - Rebuilding the entire UI when switching theme — use
restyle()/styled(...)and reuse the components.