# Desplazable

> Desplaza el contenido que no cabe. Un componente nativo de Pyzed para GUIs de escritorio en Python, con vista previa, ejemplos y su API.

Source: https://albakore.github.io/pyzed/es/library/scrollable/

:::tip[En pocas palabras]
Te deja desplazar el contenido que no cabe, con una barra de desplazamiento.
:::

Hace que su contenido se pueda desplazar en vertical, en horizontal o en `"both"`. Dale un `id` para desplazarlo desde código (`pz.Command.scroll_to`), `anchor_bottom=True` para quedarse al final (chats, registros), y personaliza el carril y la barra con el tema o tus colores.

`pz.scrollable` · Categoría: [Disposición](https://albakore.github.io/pyzed/es/library/#disposición) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#scrollable)

**Código:**

```python
pz.container(pz.scrollable(
    pz.column([ui.list_item(f"Item {i}", on_open, icon="file", inset=True) for i in range(1, 30)]),
    height=220,
), width=300)
```

## Cuándo usarlo

- Para listas largas, documentos y cualquier contenido más alto que su espacio.

## Uso

```python
import pyzed as pz
from pyzed import ui

pz.container(pz.scrollable(
    pz.column([ui.list_item(f"Item {i}", on_open, icon="file", inset=True) for i in range(1, 30)]),
    height=220,
), width=300)
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Dirección

```python
pz.container(pz.scrollable(pz.column([ui.list_item(f"Item {i}", icon="file", inset=True)
                                       for i in range(1, 30)]), height=130), width=240)
```

```python
pz.container(pz.scrollable(pz.container(pz.row([ui.chip(f"tag {i}") for i in range(1, 25)], spacing=6),
                                        padding=(0, 0, 14, 0)),
                           direction="horizontal"), width=300)
```

## Eventos

Desplazable tiene **1 evento propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | El handler recibe | Cuándo |
| --- | --- | --- |
| `on_scroll` | `(info)` | Callable que recibe un dict con `x`, `y`, `relative_x`, `relative_y`, `width`, `height`, `content_width` y `content_height`. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Feed(pz.App):
    def __init__(self):
        self.items = [f"Post {i}" for i in range(1, 30)]
        self.at_end = False

    def scrolled(self, info):            # on_scroll: x, y, relative_x, relative_y, sizes
        self.at_end = info["relative_y"] > 0.95

    def view(self):
        return pz.column([
            pz.scrollable(pz.column([ui.list_item(p, icon="file") for p in self.items]),
                          height=200, on_scroll=self.scrolled),
            ui.muted("You reached the end" if self.at_end else "Scroll down"),
        ], spacing=6, width=300)
```

**Declarativo:**

```python
from dataclasses import dataclass

@dataclass
class Scrolled:
    info: dict

class Feed(pz.App):
    items = [f"Post {i}" for i in range(1, 30)]

    def update(self, message):
        match message:
            case Scrolled(info) if info["relative_y"] > 0.95:
                self.items = self.items + [f"Post {len(self.items) + 1}"]   # load more

    def view(self):
        return pz.scrollable(pz.column([ui.list_item(p) for p in self.items]), height=200,
                             on_scroll=Scrolled)
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    progress: float = 0.0

def view(state, set_state):
    return pz.column([
        ui.progress(state.progress),
        pz.scrollable(pz.column([ui.list_item(f"Post {i}") for i in range(30)]), height=200,
                      on_scroll=lambda info: set_state(progress=info["relative_y"])),
    ], spacing=6, width=300)
```

## Propiedades y API

### `pz.scrollable`

```python
scrollable(
    content,
    *,
    direction='vertical',
    width=None,
    height=None,
    padding=None,
    id=None,
    anchor_bottom=False,
    rail=None,
    scroller=None,
    scroller_hover=None,
    scrollbar_width=8.0,
    scroller_width=None,
    margin=0.0,
    on_scroll=None,
)
```

Hace desplazable su contenido.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `content` | *obligatorio* | Contenido: un `Widget`, un texto o un número (se convierte en texto). |
| `direction` | `"vertical"` | `"vertical"`, `"horizontal"` o `"both"`. |
| `width` | `None` | Ancho: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `height` | `None` | Alto: píxeles, `"fill"`, `"shrink"` o `"fill:N"` (proporción). |
| `padding` | `None` | Relleno interior: `8`, `(vertical, horizontal)` o `(arriba, derecha, abajo, izquierda)`. |
| `id` | `None` | Identificador estable para enfocarlo o desplazarlo con un `Command`. |
| `anchor_bottom` | `False` | Mantiene el scroll pegado al final (logs, terminales, chats). |
| `rail` | `None` | Color del carril de la barra. |
| `scroller` | `None` | Color del tirador. |
| `scroller_hover` | `None` | Color del tirador al pasar el ratón. |
| `scrollbar_width` | `8.0` | Ancho de la barra. |
| `scroller_width` | `None` | Ancho del tirador (por defecto, el de la barra). |
| `margin` | `0.0` | Margen entre la barra y el contenido. |

Eventos: `on_scroll` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#scrollable)

## Relacionados

- [Columna](https://albakore.github.io/pyzed/es/library/column/): Apila los hijos en vertical.
- [Fila de lista](https://albakore.github.io/pyzed/es/library/list-item/): Una fila de lista con icono, texto y un hueco al final.
