Skip to content
CrossFly is 100% open sourceFollow us on GitHub
CrossFlyCrossFly
Get started

This page was machine-translated from Portuguese and may contain errors. The Portuguese version is canonical.

How to make a Component scrollable and adjust the overscroll

Purpose. Any Component can become a scrollable container: just declare the direction with setScrollable(ScrollDirection). If the content (the sum of the children’s heights) exceeds the visible area, the ScrollEngine handles pan, momentum, fling, and the overscroll (elastic effect when pulling beyond the limit).

APIs used

  • Component.setScrollable(ScrollDirection dir, ScrollEngine... engine) — enables scrolling. engine is optional (default: a new ScrollEngine). Pass null as dir to disable.
  • UIConstants.ScrollDirection — enum with three values: HORIZONTAL, VERTICAL, BOTH.
  • Component.isScrollable() — whether the component is scrollable.
  • Component.scrollable() — returns the Scrollable object (with .engine), or null.
  • Component.setShowScrollPosition(boolean) — shows/hides the scroll position indicator.
  • ScrollEngine.setOverscroll(boolean x, boolean y) — turns the elastic effect on/off per axis. Default: both true.
  • ScrollEngine.setupOverscroll(float distance, float speedMin, float speedMax) — adjusts the overscroll distance and return speed.
  • ScrollEngine.setScrollListener(ScrollListener listener) — callback on every offset change (receives vx, vy).
  • ScrollEngine.scrollTo(float x, float y) / scrollToStartSmooth() / scrollToEndSmooth() — repositions the scroll.
  • ScrollEngine.setOverscrollEffect(OverscrollEffect effect) — static: sets/disables (null) the global gray edge curve; customizable via new OverscrollEffect().setColor(...).setMaxAlpha(...).setMaxArcHeight(...).

Complete example (copy, paste and run)

package com.exemplo;

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

/** Runnable main screen. Point the launcher (classname) and run: 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);   // scrolls on the Y axis

      // optional tweaks to the scroll engine:
      painel.scrollable().engine.setOverscroll(true, false);   // elastic only on the vertical
      painel.setShowScrollPosition(true);                       // position indicator
      painel.scrollable().engine.setScrollListener((vx, vy) ->
         Debug.log("scrollY = " + vy));                         // reacts to scroll

      add(LAY_FILL, painel);
   }
}

The snippet below shows only the core. To run it, place it inside the MainWindow skeleton above.

Minimal snippet

// verified in source: Component.setScrollable (line ~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);   // scrolls on the Y axis

// optional tweaks to the scroll engine:
painel.scrollable().engine.setOverscroll(true, false);   // elastic only on the vertical
painel.setShowScrollPosition(true);                       // position indicator
painel.scrollable().engine.setScrollListener((vx, vy) ->
   Debug.log("scrollY = " + vy));                         // reacts to scroll

layout.add(1f, painel);

Repositioning by code:

painel.scrollable().engine.scrollToStartSmooth();   // scrolls back to top with animation
painel.scrollable().engine.scrollTo(0, 500);        // jumps to offset y=500 px

Honest note: there is no ready-made pull-to-refresh

The framework does not offer a ready-made “pull-to-refresh” widget. What exists is the overscroll effect (elastic curve when pulling beyond the limit), which is purely visual/physical — it does not expose a “released after pulling X pixels” callback for you to trigger a refresh. If you need that behavior, you will have to build it manually by monitoring the offset via setScrollListener and detecting overscroll beyond a threshold. For large lists with data reload, prefer VirtualListView.reloadData() triggered by a button or your own gesture.

Go deeper

  • Huge lists come scrollable by default (the VirtualListView calls setScrollable(VERTICAL) internally): see lista-virtual-grande.md.
Was this page helpful?