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.

10. Making it responsive

What you will learn: make the app adapt to any screen without a single fixed pixel. Prerequisites: Persisting data.

Complete example (copy, paste and run)

An adaptive app: onReposition() swaps the arrangement by orientation (2 columns in landscape, 1 in portrait) without recreating state, using Relative/Gap and Screen. Compiles as is.

package com.exemplo;

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

public class MainWindow extends Window
{
   private final Component painel = new Component();
   private final Component listaBox = new Component();
   private final Component detalheBox = new Component();

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

      listaBox.setLayout(new VerticalLayout());
      listaBox.add(LAY_AUTO, new Label("Lista"));

      detalheBox.setLayout(new VerticalLayout());
      detalheBox.add(LAY_AUTO, new Label("Detalhe"));

      boolean largo = Screen.minSize >= 600;   // breakpoint: smaller side (stable on rotation)
      add(LAY_AUTO, new Label(largo ? "Tablet/desktop" : "Telefone"));

      add(LAY_FILL, painel);
      onReposition();                           // initial arrangement
   }

   @Override
   protected void onReposition() throws Exception
   {
      painel.removeAll();
      if (Screen.isLandscape) {                 // 2 columns: list | detail
         painel.setLayout(new HorizontalLayout());
         painel.add(0.4f, listaBox);
         painel.add(0.6f, detalheBox);
      } else {                                  // 1 column
         painel.setLayout(new VerticalLayout());
         painel.add(LAY_FILL, listaBox);
      }
      painel.setValidLayout(false);
   }
}

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

The tools

Relative.ofFont(1.5f);                     // scales with the font/DPI
Relative.ofScreen(0.8f, ScreenSize.MIN);   // fraction of the SMALLER side (adapts portrait/landscape)
Gap.ofFont(0.5f);                          // spacing that scales
add(LAY_FILL, comp);                       // one elastic area per axis

Breakpoint with Screen.minSize

Use the smaller side — stable when the device rotates:

boolean largo = Screen.minSize >= 600;   // tablet/desktop

Swapping the arrangement by orientation — onReposition()

When the structure must change (1 column in portrait, 2 in landscape), override onReposition() (called on resize) — without recreating state:

@Override protected void onReposition() throws Exception {
   painel.removeAll();
   if (Screen.isLandscape) {                    // 2 columns: list | detail
      painel.setLayout(new HorizontalLayout());
      painel.add(0.4f, listaBox);
      painel.add(0.6f, detalheBox);
   } else {                                      // 1 column
      painel.setLayout(new VerticalLayout());
      painel.add(LAY_FILL, listaBox);
   }
}

What you build in this step

The app becomes adaptive — phone in portrait, tablet/desktop in landscape — with no fixed pixels.

Recap

Relative/Gap/LAY_FILL = automatic responsiveness; Screen.minSize = breakpoint; onReposition() swaps the arrangement while preserving state.

Next steps

→ Testing your app

See also

Was this page helpful?