# How to make a Component scrollable and adjust the overscroll

> Enable scrolling on any Component with setScrollable and configure the elastic edge effect.

Source: https://crossfly.dev/docs/cookbook/lists/rolagem-e-overscroll — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# 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)
```java
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
```java
// 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:

```java
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](/docs/cookbook/lists/lista-virtual-grande).
