Voltar para Home
por Eliezer Brasilian

Veja como esconder e exibir componentes de forma reativa com Show.when

Veja como esconder e exibir componentes de forma reativa com Show.when

Nos posts anteriores da série vimos o State puro (contador) e o ComputedState (tamanho de texto). Agora vamos ver um padrão diferente, mas igualmente essencial em qualquer UI: mostrar ou esconder um componente inteiro dependendo de uma condição. No Megalodonte, isso é resolvido com o Show.when.

O exemplo de hoje é bem lúdico: um jogo de "esconde-esconde" simples. Um botão, e um texto que aparece e desaparece cada vez que você clica nele.

O problema

Em UIs imperativas, esconder um componente normalmente envolve chamar algo como setVisible(false) ou remover manualmente o nó da árvore de renderização — e depois lembrar de recolocá-lo de volta corretamente quando a condição mudar. É fácil esquecer um caso, ou deixar o componente "vivo" (consumindo memória, escutando eventos) mesmo quando está invisível.

Com Show.when, você declara a condição, e o framework decide quando montar e desmontar o componente.

O código

Main.java — o mesmo ponto de entrada padrão dos exemplos anteriores:

package my_app;

import megalodonte.ListenerManager;
import megalodonte.application.MegalodonteApp;
import megalodonte.base.theme.ThemeManager;
import megalodonte.theme.DefaultTheme;

public class Main {

    static void main() {
        ThemeManager.setTheme(new DefaultTheme());

        MegalodonteApp.run(context -> context.useView(new HomeScreen()), ev->{
            if(ev == MegalodonteApp.Event.CloseRequest){
                System.out.println("Clicked on X - close application");
                ListenerManager.disposeAll();
            }
        });
    }
}

HomeScreen.java — onde o Show.when entra em ação:

package my_app;

import megalodonte.base.components.Component;
import megalodonte.base.components.ScreenComponent;
import megalodonte.base.state.State;
import megalodonte.components.Button;
import megalodonte.components.Text;
import megalodonte.components.layout_components.Container;
import megalodonte.props.ContainerProps;
import megalodonte.v2.Show;

public class HomeScreen implements ScreenComponent {
    State<Boolean> isVisible = new State<>(false);

    @Override
    public Component render() {
      return new Container(new ContainerProps().paddingAll(25))
              .children(
                      new Button("Hide and seek - game").onClick(this::toggleVisibility),
                      Show.when(isVisible, ()-> new Text("You catch me"))
                      );
    }

    void toggleVisibility(){
        isVisible.set(!isVisible.get());
    }
}

Como funciona, na prática

  • isVisible é um State<Boolean> comum — o mesmo tipo de estado que já usamos no contador, só que guardando true/false em vez de um número.
  • Show.when(isVisible, () -> new Text("You catch me")) recebe o estado booleano e uma função (Supplier<Component>) que constrói o componente a ser exibido. Enquanto isVisible for false, o Text nem chega a ser criado. Quando vira true, o Show chama a função, monta o componente e o insere na tela.
  • O método toggleVisibility() só inverte o valor booleano com isVisible.set(!isVisible.get()). Ele não sabe (nem precisa saber) que existe um componente sendo mostrado ou escondido — só muda o estado, e a UI reage.
  • Como essa é a variante reativa do Show.when (que recebe um State<Boolean>, e não um boolean fixo), o framework reavalia a condição toda vez que o estado muda — é isso que permite o clique no botão alternar a visibilidade infinitamente.

Por que isso importa

Esse padrão é a base de praticamente qualquer UI condicional: mensagens de erro que só aparecem quando há um erro, painéis que se expandem/recolhem, campos de formulário que dependem de uma escolha anterior, loaders que somem quando os dados chegam. Em vez de gerenciar visibilidade manualmente, você declara "isso aparece quando X é verdadeiro" e deixa o framework cuidar do resto.


Publiquei também a versão desse post no Reddit, com mais contexto sobre o ecossistema Megalodonte:

Link do post no Reddit: https://www.reddit.com/r/JavaFX/s/ndzLI534Ym