Back to articles

Quem realmente controla os Slivers?

Do gesto do usuário até o cálculo do layout: entenda o pipeline completo do scroll no Flutter.

5 min de leitura16 leituras
Flutter
Índice

Antes de tudo, esqueça o ListView

Nos artigos anteriores vimos que:

ListView.builder(...)

é apenas uma abstração.

Na prática, o Flutter trabalha com algo muito mais próximo disso:

CustomScrollView(
  slivers: [
    SliverList(...),
  ],
)

Ou seja: Quem controla o scroll não é o ListView.

É o CustomScrollView.


O pipeline completo

A melhor forma de entender isso é visualizar o fluxo inteiro.

Usuário
  ↓
GestureDetector
  ↓
Scrollable
  ↓
ScrollPosition
  ↓
Viewport
  ↓
Sliver 1
Sliver 2
Sliver 3
  ↓
Tela

Cada bloco possui uma responsabilidade. E quase nenhum deles conhece detalhes dos outros.


Tudo começa com um gesto

Quando você arrasta o dedo (⬇️) o Flutter não move a tela imediatamente.

Primeiro ele precisa descobrir:

  • direção;
  • velocidade;
  • aceleração;
  • momento em que o dedo foi solto.

Esse trabalho pertence ao sistema de gestos (GestureDetector).

Depois disso, entra em ação o widget mais importante do scroll: Scrollable.


O Scrollable

Pouca gente utiliza essa classe diretamente. Mas praticamente todas as listas do Flutter possuem um Scrollable.

Por exemplo:

ListView(...)

internamente cria um Scrollable.

Assim como:

GridView(...)
// e
CustomScrollView(...)

Todos eles utilizam o mesmo mecanismo.

O Scrollable é responsável por transformar o gesto em movimentação. Mas ele ainda não sabe onde a tela está. Para isso existe outra classe.


ScrollPosition

Imagine que o scroll seja apenas um número.

0 px

Depois:

150 px

Depois:

1200 px

Quem guarda esse valor é a ScrollPosition.

Ela representa exatamente onde estamos dentro da área rolável.

Quando fazemos:

final controller = ScrollController();

estamos, na prática, criando um objeto que controla uma ou mais ScrollPosition.

É por isso que conseguimos fazer coisas como:

controller.jumpTo(300);

ou

controller.animateTo(
  0,
  duration: Duration(milliseconds: 300),
  curve: Curves.ease,
);

Esses métodos não movem widgets. Eles apenas alteram a posição do scroll.


O Viewport recebe a nova posição

Agora imagine que a posição mudou para:

1450 px

O Viewport recebe essa informação. E faz uma pergunta muito simples:

Quais Slivers aparecem nessa posição?

Ele não conhece Lists.

Não conhece Grids.

Não conhece AppBars.

Ele apenas conhece uma sequência de Slivers.


Como um Sliver sabe o que fazer?

É aqui que entra uma das classes menos conhecidas do Flutter.

SliverConstraints.

Sempre que um Sliver precisa calcular seu layout, ele recebe um objeto parecido com este:

void performLayout() {
  final constraints = this.constraints;
}

Dentro dele existem informações como:

  • Posição atual do scroll;
  • Tamanho do viewport;
  • Direção do scroll;
  • Espaço restante disponível.

Em outras palavras: O Flutter entrega todo o contexto necessário para que aquele Sliver tome decisões.

É como se dissesse:

Você possui 640 pixels visíveis. O scroll está na posição 1200. Descubra quanto espaço você ocupa.


A resposta é um SliverGeometry

Depois de fazer seus cálculos, o Sliver responde.

Mas ele não responde com widgets, nem com pixels.

Ele responde com um objeto chamado: SliverGeometry.

Esse objeto informa coisas como:

  • Quanto espaço ele ocupa;
  • Quanto conteúdo ainda existe;
  • Quanto pode ser pintado;
  • Quanto pode ser rolado.

Visualmente podemos imaginar essa conversa assim:

Viewport
  ↓
SliverConstraints
  ↓
SliverList
  ↓
SliverGeometry
  ↓
Viewport

É literalmente um diálogo entre o Viewport e cada Sliver.


Isso acontece para todos os Slivers

Imagine esta tela:

CustomScrollView(
  slivers: [
    SliverAppBar(...),
    SliverList(...),
    SliverGrid(...),
    SliverToBoxAdapter(...),
  ],
)

O Viewport conversa com cada um deles.

AppBar
  ↓
Geometry List
  ↓
Geometry Grid
  ↓
Geometry Banner
  ↓
Geometry

Depois soma todas essas respostas.

Só então ele sabe exatamente o que desenhar.


O que o ScrollController realmente faz?

Depois de entender esse pipeline fica fácil perceber que o ScrollController não controla Slivers. Ele controla a posição do scroll.

Quando você escreve:

controller.animateTo(...)

o fluxo é mais ou menos este:

ScrollController
  ↓
ScrollPosition
  ↓
Viewport
  ↓
Slivers recalculam
  ↓
Nova tela

Perceba que o Controller nunca conversa diretamente com um SliverList.

Ele apenas altera a posição.

Todo o restante acontece automaticamente.


O verdadeiro modelo mental

Quando você desliza o dedo na tela, o Flutter não “move widgets”.

O que realmente acontece é:

Gesture
  ↓
ScrollPosition
  ↓
Viewport
  ↓
SliverConstraints
  ↓
Cada Sliver calcula seu layout
  ↓
SliverGeometry
  ↓
Viewport monta a nova tela

Depois que esse fluxo fica claro, APIs como SliverPersistentHeader, NestedScrollView, SliverFillRemaining e até comportamentos como o colapso da SliverAppBar deixam de parecer mágicos.

Todos utilizam exatamente o mesmo mecanismo.


Conclusão

Neste artigo, deixamos de olhar para os widgets e passamos a enxergar o motor que realmente move uma interface rolável.

Vimos que o ScrollController altera a posição do scroll, a ScrollPosition representa onde estamos, o Viewport coordena a área visível e cada Sliver recebe um conjunto de SliverConstraints para calcular seu layout, respondendo com uma SliverGeometry.

Esse pipeline é um dos pilares da arquitetura de renderização do Flutter e explica por que o framework consegue combinar diferentes tipos de conteúdo em uma única experiência de scroll, mantendo alta performance.

No próximo artigo vamos sair da teoria e colocar tudo isso em prática.

Agora que entendemos como o Flutter coordena os Slivers, chegou a hora de construir uma tela real usando CustomScrollView, combinando SliverAppBar, SliverList, SliverGrid e outros Slivers para ver essa arquitetura funcionando na prática.

Compartilhar:XLinkedInWhatsApp
Wellington Eugenio dos Santos

Escrito por Wellington Eugenio dos Santos

Engenheiro de Software focado em criar soluções robustas de alto desempenho para Web e Mobile.
Criador de bibliotecas open-source como signal_form e lucid_validation.