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.

Responsiveness in every layout

CrossFly uses logical pixels and recomputes the layout on rotation/resize. If you follow the principles below, the screen re-adapts on its own — with no resize code.

This is the practical summary. The complete guide, with an example in each layout and an end-to-end screen example, is Chapter 36 — Layout and Responsiveness Best Practices.

The 5 principles

  1. Never position in fixed pixels. Use fractions, Relative and LAY_FILL/LAY_AUTO / RelSize.FILL.
  2. Let the layout measure. LAY_AUTO, RelSize.AUTOSIZE and Relative.AUTO report the natural size.
  3. Spacing scales too. Padding (ingap) and margin (outgap) via Gap.ofFont(...) / Gap.ofScreen(...).
  4. One “elastic” area. Mark one component with LAY_FILL (Vertical/Horizontal) to absorb the remainder.
  5. Resize is automatic — if you used the items above. Only manual positioning (setBounds) requires code.

The central tool: Relative

Form Result
Relative.ofFont(1.5f) 1.5 × font height (scales with the font/DPI)
Relative.ofScreen(0.8f) 80% of the screen dimension
Relative.ofScreen(0.5f, ScreenSize.MIN) 50% of the smaller side (adapts to portrait/landscape)
Relative.FULL / AUTO / CENTER fills the parent / content size / centers

Full example (copy, paste and run)

package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;

/** Runnable main screen. Point the launcher (classname) and run: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   private Component painel;      // rearranged on each resize/rotation
   private Component lista;
   private Component detalhe;

   @Override
   public void onShow() throws Exception
   {
      super.onShow();

      lista   = new Label("Lista");
      detalhe = new Label("Detalhe");

      painel = new Component();
      setLayout(new VerticalLayout(Position.START, Position.START));
      add(LAY_FILL, painel);
      // onReposition() is called on the first layout and on each resize/rotation:
      // it chooses the panel arrangement according to the orientation.
   }

   @Override
   protected void onReposition() throws Exception
   {
      painel.removeAll();
      if (Screen.isLandscape) {
         painel.setLayout(new HorizontalLayout());
         painel.add(0.5f, lista); painel.add(0.5f, detalhe);
      } else {
         painel.setLayout(new VerticalLayout());
         painel.add(LAY_FILL, lista); painel.add(LAY_AUTO, detalhe);
      }
   }
}

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

When the arrangement should CHANGE by orientation

Override Window.onReposition() (called before the relayout) and re-pick the layout:

@Override protected void onReposition() throws Exception {
   painel.removeAll();
   if (Screen.isLandscape) {
      painel.setLayout(new HorizontalLayout());
      painel.add(0.5f, lista); painel.add(0.5f, detalhe);
   } else {
      painel.setLayout(new VerticalLayout());
      painel.add(LAY_FILL, lista); painel.add(LAY_AUTO, detalhe);
   }
}

Breakpoints: use Screen.minSize (the smaller side is stable across orientations), e.g.: tablet = Screen.minSize >= 600.

See also

Was this page helpful?