Pular para o conteúdo
CrossFly é 100% open sourceSiga no GitHub
CrossFlyCrossFly
Começar

A pilha de janelas

Entender o modelo evita a maioria dos bugs de navegação.

O modelo (LIFO)

O EventsProcessor mantém uma pilha de Window. A janela do topo é a que recebe eventos e é pintada por cima. As de baixo continuam vivas (não são destruídas), apenas cobertas.

┌─────────────┐  ← topo: recebe toque/teclado, é pintada
│ TelaDetalhe │
├─────────────┤
│ TelaLista   │  ← coberta, viva
├─────────────┤
│ TelaHome    │  ← base
└─────────────┘
  • show() → push: registra no EventsProcessor, chama onShow().
  • hide() → pop: desregistra, chama onRemove(); a janela de baixo volta ao topo.

Ciclo de vida por janela

Método Quando Uso
onShow() ao entrar na pilha montar a UI (sempre super.onShow())
onReposition() ao redimensionar/rotacionar reorganizar/recalcular layout
onRemove() ao sair da pilha liberar timers, cursores, listeners

Fullscreen vs popup

A mesma classe Window pode ser tela cheia ou popup — depende do WindowStyle (widthRatio/heightRatio < 1 ⇒ popup; ver Diálogos e modais). Popups ficam sobre a tela anterior (que continua visível atrás).

Botão Voltar (Android) e tocar fora

  • O botão físico Voltar é capturado pela aplicação e, por padrão, faz hide() da janela do topo.
  • Em um popup com canHide = true, tocar fora fecha o popup.
  • Para impedir a saída (ex.: confirmação de descarte), trate a intenção antes de deixar hide() ocorrer.

Exemplo completo (copiar, colar e rodar)

Demonstra push/pop na pilha e uma transição de entrada configurada no WindowStyle da tela empilhada.

package com.exemplo;

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

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      add(LAY_AUTO, new Label("Base da pilha (MainWindow)"));

      Button empilhar = new Button("Empilhar tela (push)");
      empilhar.onAction(c -> new TelaEmpilhada().show());   // push: entra no topo da pilha
      add(LAY_AUTO, empilhar);
   }
}

/** Tela que entra no topo com uma transição e volta com hide() (pop). */
class TelaEmpilhada extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      // transição de entrada/saída desta janela (a de baixo continua viva atrás)
      getStyle().transition(UIConstants.Transition.SLIDE_LEFT);
      setLayout(new VerticalLayout());

      add(LAY_AUTO, new Label("Topo da pilha — a tela de baixo continua viva"));

      Button voltar = new Button("Voltar (pop)");
      voltar.onAction(c -> hide());   // pop: sai da pilha, a de baixo volta ao topo
      add(LAY_AUTO, voltar);
   }
}

Os trechos abaixo mostram só o miolo (o que vai dentro de onShow()). Para rodar, coloque-os no esqueleto MainWindow acima.

Transições

A animação de entrada/saída vem de WindowStyle.transition (UIConstants.Transition): NONE (padrão), FADE, SLIDE_LEFT/RIGHT/UP/DOWN, SCALE, SCALE_DOWN. Pickers usam FADE por padrão.

getStyle().transition = UIConstants.Transition.SLIDE_LEFT;   // desliza ao abrir

Boas práticas

  • Não segure referências às janelas de baixo além do necessário — deixe-as serem coletadas ao hide().
  • Todo show() deve ter um hide() correspondente (evite empilhar telas sem retorno).

Erros comuns

  • Reconstruir a UI em onReposition() sem preservar estado (rolagem, seleção).
  • Assumir que a janela de baixo foi destruída ao abrir outra — ela continua viva.

Veja também

Esta página foi útil?