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

Como tornar um Component rolável e ajustar o overscroll

Propósito. Qualquer Component pode virar um contêiner rolável: basta declarar a direção com setScrollable(ScrollDirection). Se o conteúdo (a soma das alturas dos filhos) exceder a área visível, o ScrollEngine cuida de pan, momentum, fling e do overscroll (efeito elástico ao puxar além do limite).

APIs usadas

  • Component.setScrollable(ScrollDirection dir, ScrollEngine... engine) — habilita scroll. engine é opcional (default: ScrollEngine novo). Passe null como dir para desabilitar.
  • UIConstants.ScrollDirection — enum com três valores: HORIZONTAL, VERTICAL, BOTH.
  • Component.isScrollable() — se o componente está rolável.
  • Component.scrollable() — retorna o objeto Scrollable (com .engine), ou null.
  • Component.setShowScrollPosition(boolean) — mostra/oculta o indicador de posição de scroll.
  • ScrollEngine.setOverscroll(boolean x, boolean y) — liga/desliga o efeito elástico por eixo. Default: ambos true.
  • ScrollEngine.setupOverscroll(float distance, float speedMin, float speedMax) — ajusta distância e velocidade de retorno do overscroll.
  • ScrollEngine.setScrollListener(ScrollListener listener) — callback a cada mudança de offset (recebe vx, vy).
  • ScrollEngine.scrollTo(float x, float y) / scrollToStartSmooth() / scrollToEndSmooth() — reposiciona o scroll.
  • ScrollEngine.setOverscrollEffect(OverscrollEffect effect) — estático: define/desativa (null) a curva cinza de borda global; customizável via new OverscrollEffect().setColor(...).setMaxAlpha(...).setMaxArcHeight(...).

Exemplo completo (copiar, colar e rodar)

package com.exemplo;

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

/** 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());

      Component painel = new Component();
      painel.setLayout(new GridLayout(Position.CENTER, Position.START));
      for (int i = 0; i < 60; i++)
         painel.add(.95f, new Label("Linha " + i));

      painel.setScrollable(ScrollDirection.VERTICAL);   // rola no eixo Y

      // ajustes opcionais no motor de scroll:
      painel.scrollable().engine.setOverscroll(true, false);   // elástico só na vertical
      painel.setShowScrollPosition(true);                       // indicador de posição
      painel.scrollable().engine.setScrollListener((vx, vy) ->
         Debug.log("scrollY = " + vy));                         // reage ao scroll

      add(LAY_FILL, painel);
   }
}

O trecho abaixo mostra só o miolo. Para rodar, coloque-o no esqueleto MainWindow acima.

Trecho mínimo

// verificado na fonte: Component.setScrollable (linha ~1027) + ScrollEngine.java
Component painel = new Component();
painel.setLayout(new GridLayout(Position.CENTER, Position.START));
for (int i = 0; i < 60; i++)
   painel.add(.95f, new Label("Linha " + i));

painel.setScrollable(ScrollDirection.VERTICAL);   // rola no eixo Y

// ajustes opcionais no motor de scroll:
painel.scrollable().engine.setOverscroll(true, false);   // elástico só na vertical
painel.setShowScrollPosition(true);                       // indicador de posição
painel.scrollable().engine.setScrollListener((vx, vy) ->
   Debug.log("scrollY = " + vy));                         // reage ao scroll

layout.add(1f, painel);

Reposicionando por código:

painel.scrollable().engine.scrollToStartSmooth();   // volta ao topo com animação
painel.scrollable().engine.scrollTo(0, 500);        // salta para offset y=500 px

Nota honesta: não há pull-to-refresh pronto

O framework não oferece um widget de “pull-to-refresh” (puxar-para-atualizar) pronto. O que existe é o efeito de overscroll (curva elástica ao puxar além do limite), que é puramente visual/físico — ele não expõe um callback de “soltou após puxar X pixels” para você disparar um refresh. Se precisar desse comportamento, terá que construí-lo manualmente monitorando o offset via setScrollListener e detectando o overscroll além de um limiar. Para listas grandes com recarga de dados, prefira VirtualListView.reloadData() acionado por um botão ou gesto próprio.

Aprofunde-se

  • Listas enormes já vêm roláveis por padrão (o VirtualListView chama setScrollable(VERTICAL) internamente): veja lista-virtual-grande.md.
Esta página foi útil?