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:ScrollEnginenovo). Passenullcomodirpara desabilitar.UIConstants.ScrollDirection— enum com três valores:HORIZONTAL,VERTICAL,BOTH.Component.isScrollable()— se o componente está rolável.Component.scrollable()— retorna o objetoScrollable(com.engine), ounull.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: ambostrue.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 (recebevx, 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 vianew 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
MainWindowacima.
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
VirtualListViewchamasetScrollable(VERTICAL)internamente): veja lista-virtual-grande.md.