Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

Skins

A Skin defines the structural visual identity of all components: shape (corners), border thickness, spacing, shadows and default icons. There are three built in: MaterialSkin, IOSSkin and FlutterSkin.

Skin ≠ colors. Skin = structure/renderer; the palette (light/dark, primary/surface…) comes from the ColorScheme/ThemeMode. A custom skin changes shape/spacing, not color.

Default skin

Skin.get() returns MaterialSkin by default — or IOSSkin automatically on iOS.

Complete example (copy, paste and run)

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // Styles
import dev.crossfly.ui.skin.*;    // Skin, MaterialSkin, IOSSkin, FlutterSkin

/** 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();
      Skin.set(new IOSSkin());   // global skin = iOS structure/shape (colors still come from the theme)
      setLayout(new VerticalLayout());

      // Buttons to switch the global skin in real time:
      Button material = new Button("Skin Material");
      material.onAction(c -> { Skin.set(new MaterialSkin()); restyle(); });
      add(LAY_AUTO, material);

      Button ios = new Button("Skin iOS");
      ios.onAction(c -> { Skin.set(new IOSSkin()); restyle(); });
      add(LAY_AUTO, ios);

      Button flutter = new Button("Skin Flutter");
      flutter.onAction(c -> { Skin.set(new FlutterSkin()); restyle(); });
      add(LAY_AUTO, flutter);

      // Skin per component: this button stays iOS even if the global one changes.
      Button fixoIos = new Button("Sempre iOS");
      fixoIos.skin(new IOSSkin());
      add(LAY_AUTO, fixoIos);
   }
}

The snippets below show only the core (what goes inside onShow()). To run them, place them in the MainWindow skeleton above.

Switch the global skin

Affects all components that do not have their own skin:

Skin.set(new IOSSkin());       // the whole UI gets the iOS look
Skin.set(new FlutterSkin());   // … or Flutter

Skin per component

Overrides the global one only in that component:

meuBotao.skin(new IOSSkin());  // this button stays iOS, the rest remains Material

Custom skin (change shape/spacing, not color)

Extend a skin and override the structure hooks:

public class RoundedSkin extends MaterialSkin {
   @Override public float borderRadius() { return 1.5f; }  // nicely rounded corners
   @Override public float borderThick()  { return 0.05f; } // thin border
}
// apply globally:
Skin.set(new RoundedSkin());

To adapt colors to light/dark, do not touch the skin — use ColorScheme/ThemeMode (see Light/dark mode).

How the layers interact

Seed color

ColorScheme (palette)

Styles (PalColor fields)

Skin (shape/spacing)

Skin.button()/label()/…

component's final ComponentStyle

In other words: the **Skin** builds the style by reading the **theme colors** — changing one does not affect the other.

Best practices

  • Choose one global skin at bootstrap; use .skin(...) per component only for exceptions.
  • Custom skin = shape/spacing/shadow. Color and light/dark = ColorScheme.

Common mistakes

  • Trying to change colors by overriding the skin — colors come from ColorScheme, not the skin.
  • Mixing different skins on the same screen without need (visual inconsistency).

See also

Was this page helpful?