Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar

Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.

La pila de ventanas

Entender el modelo evita la mayoría de los bugs de navegación.

El modelo (LIFO)

El EventsProcessor mantiene una pila de Window. La ventana de la cima es la que recibe eventos y se pinta por encima. Las de abajo siguen vivas (no se destruyen), solo cubiertas.

┌─────────────┐  ← topo: recebe toque/teclado, é pintada
│ TelaDetalhe │
├─────────────┤
│ TelaLista   │  ← coberta, viva
├─────────────┤
│ TelaHome    │  ← base
└─────────────┘
  • show() → push: registra en el EventsProcessor, llama a onShow().
  • hide() → pop: desregistra, llama a onRemove(); la ventana de abajo vuelve a la cima.

Ciclo de vida por ventana

Método Cuándo Uso
onShow() al entrar en la pila montar la UI (siempre super.onShow())
onReposition() al redimensionar/rotar reorganizar/recalcular layout
onRemove() al salir de la pila liberar timers, cursores, listeners

Fullscreen vs popup

La misma clase Window puede ser pantalla completa o popup — depende del WindowStyle (widthRatio/heightRatio < 1 ⇒ popup; ver Diálogos y modales). Los popups quedan sobre la pantalla anterior (que sigue visible detrás).

Botón Atrás (Android) y tocar fuera

  • El botón físico Atrás es capturado por la aplicación y, por defecto, hace hide() de la ventana de la cima.
  • En un popup con canHide = true, tocar fuera cierra el popup.
  • Para impedir la salida (ej.: confirmación de descarte), maneja la intención antes de dejar que ocurra hide().

Ejemplo completo (copiar, pegar y ejecutar)

Demuestra push/pop en la pila y una transición de entrada configurada en el WindowStyle de la pantalla apilada.

package com.exemplo;

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

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: 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 al tope de la pila
      add(LAY_AUTO, empilhar);
   }
}

/** Pantalla que entra al tope con una transición y vuelve con hide() (pop). */
class TelaEmpilhada extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      // transición de entrada/salida de esta ventana (la de abajo sigue viva detrá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: sale de la pila, la de abajo vuelve al tope
      add(LAY_AUTO, voltar);
   }
}

Los fragmentos siguientes muestran solo el núcleo (lo que va dentro de onShow()). Para ejecutar, colócalos en el esqueleto MainWindow anterior.

Transiciones

La animación de entrada/salida viene de WindowStyle.transition (UIConstants.Transition): NONE (por defecto), FADE, SLIDE_LEFT/RIGHT/UP/DOWN, SCALE, SCALE_DOWN. Los pickers usan FADE por defecto.

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

Buenas prácticas

  • No mantengas referencias a las ventanas de abajo más de lo necesario — deja que se recolecten al hide().
  • Todo show() debe tener un hide() correspondiente (evita apilar pantallas sin retorno).

Errores comunes

  • Reconstruir la UI en onReposition() sin preservar el estado (scroll, selección).
  • Asumir que la ventana de abajo se destruyó al abrir otra — sigue viva.

Ver también

¿Te resultó útil esta página?